/*
 * Copyright (C) 2012 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.camera;

import android.annotation.TargetApi;
import android.app.Activity;
import android.content.ContentProviderClient;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences.Editor;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.graphics.SurfaceTexture;
import android.graphics.drawable.Drawable;
import android.hardware.Camera.CameraInfo;
import android.hardware.Camera.Parameters;
import android.hardware.Camera.Size;
import android.hardware.Camera.Area;    // SPRD: add for multi-focus
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.location.Location;
import android.media.CameraProfile;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.MessageQueue;
import android.os.SystemClock;
import android.provider.MediaStore;
import android.util.Log;
import android.view.KeyEvent;
import android.view.OrientationEventListener;
import android.view.View;
import android.view.WindowManager;
import android.view.LayoutInflater;
import android.widget.ImageView;
import android.widget.FrameLayout;

import com.android.camera.CameraManager.CameraAFCallback;
import com.android.camera.CameraManager.CameraAFMoveCallback;
import com.android.camera.CameraManager.CameraPictureCallback;
import com.android.camera.CameraManager.CameraProxy;
import com.android.camera.CameraManager.CameraShutterCallback;
import com.android.camera.PhotoModule.NamedImages.NamedEntity;
import com.android.camera.exif.ExifInterface;
import com.android.camera.exif.ExifTag;
import com.android.camera.exif.Rational;
import com.android.camera.ui.CountDownView.OnCountDownFinishedListener;
import com.android.camera.ui.ModuleSwitcher;
import com.android.camera.ui.RotateTextToast;
import com.android.camera.util.ApiHelper;
import com.android.camera.util.CameraUtil;
import com.android.camera.util.GcamHelper;
import com.android.camera.util.UsageStatistics;
import com.android.camera2.R;
import com.sprd.camera.ZSLController;
import com.android.camera.util.Tuple;               // SPRD: porting multi-focus
import com.android.camera.ui.FreezeFrameDisplayView;
import com.android.camera.ui.Rotatable;
import com.sprd.camera.AlertDialogPopup;          // SPRD: for restore preferences

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.List;
import java.util.Vector;
import java.util.ArrayList;

public class PhotoModule
        implements CameraModule,
        PhotoController,
        FocusOverlayManager.Listener,
        CameraPreference.OnPreferenceChangedListener,
        ShutterButton.OnShutterButtonListener,
        MediaSaveService.Listener,
        OnCountDownFinishedListener,
        SensorEventListener {

    private static final boolean DEBUG = true;
    private static final String TAG = "CAM_PhotoModule";

    // We number the request code from 1000 to avoid collision with Gallery.
    private static final int REQUEST_CROP = 1000;

    private static final int SETUP_PREVIEW = 1;
    private static final int FIRST_TIME_INIT = 2;
    private static final int CLEAR_SCREEN_DELAY = 3;
    private static final int SET_CAMERA_PARAMETERS_WHEN_IDLE = 4;
    private static final int SHOW_TAP_TO_FOCUS_TOAST = 5;
    private static final int SWITCH_CAMERA = 6;
    private static final int SWITCH_CAMERA_START_ANIMATION = 7;
    private static final int CAMERA_OPEN_DONE = 8;
    private static final int OPEN_CAMERA_FAIL = 9;
    private static final int CAMERA_DISABLED = 10;
    private static final int SWITCH_TO_GCAM_MODULE = 11;

    // The subset of parameters we need to update in setCameraParameters().
    private static final int UPDATE_PARAM_INITIALIZE = 1;
    private static final int UPDATE_PARAM_ZOOM = 2;
    private static final int UPDATE_PARAM_PREFERENCE = 4;
    private static final int UPDATE_PARAM_ALL = -1;

    // This is the delay before we execute onResume tasks when coming
    // from the lock screen, to allow time for onPause to execute.
    private static final int ON_RESUME_TASKS_DELAY_MSEC = 20;

    private static final String DEBUG_IMAGE_PREFIX = "DEBUG_";

    // copied from Camera hierarchy
    private CameraActivity mActivity;
    private CameraProxy mCameraDevice;
    private int mCameraId;
    private Parameters mParameters;
    private boolean mPaused;

    private PhotoUI mUI;
    // SPRD: bug 260858
    private boolean mEnableTopButton;
    private boolean mEnableCameraSet;

    // The activity is going to switch to the specified camera id. This is
    // needed because texture copy is done in GL thread. -1 means camera is not
    // switching.
    protected int mPendingSwitchCameraId = -1;
    private boolean mOpenCameraFail;
    private boolean mCameraDisabled;

    // When setCameraParametersWhenIdle() is called, we accumulate the subsets
    // needed to be updated in mUpdateSet.
    private int mUpdateSet;

    private static final int SCREEN_DELAY = 2 * 60 * 1000;

    private int mZoomValue;  // The current zoom value.

    private Parameters mInitialParams;
    private boolean mFocusAreaSupported;
    private boolean mMeteringAreaSupported;
    private boolean mAeLockSupported;
    private boolean mAwbLockSupported;
    private boolean mContinuousFocusSupported;

    // The degrees of the device rotated clockwise from its natural orientation.
    private int mOrientation = OrientationEventListener.ORIENTATION_UNKNOWN;
    // @{ SPRD: fix bug 255774 start
    // The orientation compensation for icons and thumbnails. Ex: if the value
    // is 90, the UI components should be rotated 90 degrees counter-clockwise.
    private int mOrientationCompensation = 0;
    // fix bug 255774 end @}

    private ComboPreferences mPreferences;
    private RotateDialogController mRotateDialog;

    private static final String sTempCropFilename = "crop-temp";

    private ContentProviderClient mMediaProviderClient;
    private boolean mFaceDetectionStarted = false;

    // SPRD: It is flag for taking picture.
    private boolean mIsTakingPicture = false;
    // mCropValue and mSaveUri are used only if isImageCaptureIntent() is true.
    private String mCropValue;
    private Uri mSaveUri;
    // SPRD:ZSLController.
    private ZSLController mZSLController;

    private Uri mDebugUri;

    // We use a queue to generated names of the images to be used later
    // when the image is ready to be saved.
    private NamedImages mNamedImages;
    private int mContinuousCaptureCount;

    private Runnable mDoSnapRunnable = new Runnable() {
        @Override
        public void run() {
            onShutterButtonClick();
        }
    };

    /**
     * An unpublished intent flag requesting to return as soon as capturing
     * is completed.
     *
     * TODO: consider publishing by moving into MediaStore.
     */
    private static final String EXTRA_QUICK_CAPTURE =
            "android.intent.extra.quickCapture";

    // The display rotation in degrees. This is only valid when mCameraState is
    // not PREVIEW_STOPPED.
    private int mDisplayRotation;
    // The value for android.hardware.Camera.setDisplayOrientation.
    private int mCameraDisplayOrientation;
    // The value for UI components like indicators.
    private int mDisplayOrientation;
    // The value for android.hardware.Camera.Parameters.setRotation.
    private int mJpegRotation;
    // Indicates whether we are using front camera
    private boolean mMirror;
    private boolean mFirstTimeInitialized;
    private boolean mIsImageCaptureIntent;

    private int mCameraState = PREVIEW_STOPPED;
    private boolean mSnapshotOnIdle = false;

    private ContentResolver mContentResolver;

    private LocationManager mLocationManager;

    private final PostViewPictureCallback
        mPostViewPictureCallback = new PostViewPictureCallback();
    private final RawPictureCallback mRawPictureCallback = new RawPictureCallback();
    private final AutoFocusCallback mAutoFocusCallback = new AutoFocusCallback();
    private final Object mAutoFocusMoveCallback =
        (ApiHelper.HAS_AUTO_FOCUS_MOVE_CALLBACK ? new AutoFocusMoveCallback() : null);

    private final CameraErrorCallback mErrorCallback = new CameraErrorCallback();

    private long mFocusStartTime;
    private long mShutterCallbackTime;
    private long mPostViewPictureCallbackTime;
    private long mRawPictureCallbackTime;
    private long mJpegPictureCallbackTime;
    private long mOnResumeTime;
    private byte[] mJpegImageData;

    // These latency time are for the CameraLatency test.
    public long mAutoFocusTime;
    public long mShutterLag;
    public long mShutterToPictureDisplayedTime;
    public long mPictureDisplayedToJpegCallbackTime;
    public long mJpegCallbackFinishTime;
    public long mCaptureStartTime;

    // This handles everything about focus.
    private FocusOverlayManager mFocusManager;

    private String mSceneMode;

    private final Handler mHandler = new MainHandler();

    private PreferenceGroup mPreferenceGroup;

    private boolean mQuickCapture;
    private SensorManager mSensorManager;
    private float[] mGData = new float[3];
    private float[] mMData = new float[3];
    private float[] mR = new float[16];
    private int mHeading = -1;
    private static final int VAL_DEFAULT_CAPTURE_COUNT = 1;
    private int mContinueTakePictureCount;

    // True if all the parameters needed to start preview is ready.
    private boolean mCameraPreviewParamsReady = false;

    private MediaSaveService.OnMediaSavedListener mOnMediaSavedListener =
            new MediaSaveService.OnMediaSavedListener() {
                @Override
                public void onMediaSaved(Uri uri) {
                    // @{ SPRD: Dont notifyNewMedia if FreezeFrame display begin
                    // if (uri != null) {
                    //     mActivity.notifyNewMedia(uri);
                    // }
                    if ((sFreezeFrameControl != null
                            && sFreezeFrameControl.isFreezeFrame()) || mIsImageCaptureIntent) {
                        if (uri != null) {
                            sFreezeFrameControl.proxyRunLoadProxy(uri);
                        } else {
                            sFreezeFrameControl.proxyDoneClicked();
                        }
                    } else {
                        if (uri != null) {
                            mActivity.notifyNewMedia(uri);
                        } // @{ SPRD: Dont notifyNewMedia if FreezeFrame display end
                    }
                }
            };

    private void checkDisplayRotation() {
        // Set the display orientation if display rotation has changed.
        // Sometimes this happens when the device is held upside
        // down and camera app is opened. Rotation animation will
        // take some time and the rotation value we have got may be
        // wrong. Framework does not have a callback for this now.
        if (CameraUtil.getDisplayRotation(mActivity) != mDisplayRotation) {
            setDisplayOrientation();
        }
        if (SystemClock.uptimeMillis() - mOnResumeTime < 5000) {
            mHandler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    checkDisplayRotation();
                }
            }, 100);
        }
    }

    /**
     * This Handler is used to post message back onto the main thread of the
     * application
     */
    private class MainHandler extends Handler {
        public MainHandler() {
            super(Looper.getMainLooper());
        }

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case SETUP_PREVIEW: {
                    setupPreview();
                    break;
                }

                case CLEAR_SCREEN_DELAY: {
                    mActivity.getWindow().clearFlags(
                            WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
                    break;
                }

                case FIRST_TIME_INIT: {
                    initializeFirstTime();
                    break;
                }

                case SET_CAMERA_PARAMETERS_WHEN_IDLE: {
                    setCameraParametersWhenIdle(0);
                    break;
                }

                case SHOW_TAP_TO_FOCUS_TOAST: {
                    showTapToFocusToast();
                    break;
                }

                case SWITCH_CAMERA: {
                    switchCamera();
                    break;
                }

                case SWITCH_CAMERA_START_ANIMATION: {
                    // TODO: Need to revisit
                    // ((CameraScreenNail) mActivity.mCameraScreenNail).animateSwitchCamera();
                    break;
                }

                case CAMERA_OPEN_DONE: {
                    onCameraOpened();
                    break;
                }

                case OPEN_CAMERA_FAIL: {
                    mOpenCameraFail = true;
                    /* SPRD :add VideoCall check toast  @{  */
                    if (mActivity.checkTelephoneVideoCall()) {
                        CameraUtil.showErrorAndFinish(mActivity,
                                R.string.in_video_call_is_running);
                    } else {
                        CameraUtil.showErrorAndFinish(mActivity,
                                R.string.cannot_connect_camera);
                    }
                    /*  }@ */
                    break;
                }

                case CAMERA_DISABLED: {
                    mCameraDisabled = true;
                    CameraUtil.showErrorAndFinish(mActivity,
                            R.string.camera_disabled);
                    break;
                }

                case SWITCH_TO_GCAM_MODULE: {
                    mActivity.onModuleSelected(ModuleSwitcher.GCAM_MODULE_INDEX);
                }
            }
        }
    }


    @Override
    public void init(CameraActivity activity, View parent) {
        mActivity = activity;
        mUI = new PhotoUI(activity, this, parent);
        mPreferences = new ComboPreferences(mActivity);
        CameraSettings.upgradeGlobalPreferences(mPreferences.getGlobal());
        mCameraId = getPreferredCameraId(mPreferences);

        mContentResolver = mActivity.getContentResolver();

        // Surface texture is from camera screen nail and startPreview needs it.
        // This must be done before startPreview.
        mIsImageCaptureIntent = isImageCaptureIntent();
        // @{ SPRD: bug 258455 begin
        // if (mIsImageCaptureIntent) {
        //    mActivity.setModuleVisble(View.INVISIBLE);
        // } // SPRD: bug 258455 end @}

        mPreferences.setLocalId(mActivity, mCameraId);
        CameraSettings.upgradeLocalPreferences(mPreferences.getLocal());
        // we need to reset exposure for the preview
        resetExposureCompensation();

        initializeControlByIntent();
        mQuickCapture = mActivity.getIntent().getBooleanExtra(EXTRA_QUICK_CAPTURE, false);
        mLocationManager = new LocationManager(mActivity, mUI);
        mSensorManager = (SensorManager)(mActivity.getSystemService(Context.SENSOR_SERVICE));
        // SPRD initialize mJpegQualityController.
        mJpegQualityController = new JpegQualityController();
        //SPRD:Add for freeze_display
        mRotateDialog = new RotateDialogController(mActivity, R.layout.rotate_dialog);
        sFreezeFrameControl = new FreezeFrameDisplayControl();
    }

    private void initializeControlByIntent() {
        mUI.initializeControlByIntent();
        if (mIsImageCaptureIntent) {
            setupCaptureParams();
        }
        // SPRD:initialize CustomController, HDR,ZSL etc.
        initializeCustomController();
        // SPRD: bug 260858
        mEnableTopButton = true;
        mEnableCameraSet = true;
    }

    private void onPreviewStarted() {
        setCameraState(IDLE);
        startFaceDetection();
        locationFirstRun();
    }

    // Prompt the user to pick to record location for the very first run of
    // camera only
    private void locationFirstRun() {
        if (RecordLocationPreference.isSet(mPreferences)) {
            return;
        }
        if (mActivity.isSecureCamera()) return;
        // Check if the back camera exists
        int backCameraId = CameraHolder.instance().getBackCameraId();
        if (backCameraId == -1) {
            // If there is no back camera, do not show the prompt.
            return;
        }
        // SPRD: hide GPS item on the 7715
        if (!CameraUtil.isSupportedGps()) {
            mPreferences.edit().putString(
                CameraSettings.KEY_RECORD_LOCATION, RecordLocationPreference.VALUE_OFF)
                .apply();
            return;
        }
        mUI.showLocationDialog();
    }

    @Override
    public void enableRecordingLocation(boolean enable) {
        setLocationPreference(enable ? RecordLocationPreference.VALUE_ON
                : RecordLocationPreference.VALUE_OFF);
    }

    @Override
    public void onPreviewUIReady() {
        startPreview();
    }

    @Override
    public void onPreviewUIDestroyed() {
        if (mCameraDevice == null) {
            return;
        }
        stopPreview();
        mCameraDevice.setPreviewTexture(null);
    }

    private void setLocationPreference(String value) {
        mPreferences.edit()
                .putString(CameraSettings.KEY_RECORD_LOCATION, value)
                .apply();
        // TODO: Fix this to use the actual onSharedPreferencesChanged listener
        // instead of invoking manually
        onSharedPreferenceChanged();
    }

    private void onCameraOpened() {
        View root = mUI.getRootView();
        // These depend on camera parameters.

        int width = root.getWidth();
        int height = root.getHeight();
        mFocusManager.setPreviewSize(width, height);
        openCameraCommon();
    }

    private void switchCamera() {
        if (mPaused) return;

        Log.v(TAG, "Start to switch camera. id=" + mPendingSwitchCameraId);
        mCameraId = mPendingSwitchCameraId;
        mPendingSwitchCameraId = -1;
        setCameraId(mCameraId);

        // from onPause
        closeCamera();
        mUI.collapseCameraControls();
        mUI.clearFaces();
        if (mFocusManager != null) mFocusManager.removeMessages();

        // Restart the camera and initialize the UI. From onCreate.
        mPreferences.setLocalId(mActivity, mCameraId);
        CameraSettings.upgradeLocalPreferences(mPreferences.getLocal());
        mCameraDevice = CameraUtil.openCamera(
                mActivity, mCameraId, mHandler,
                mActivity.getCameraOpenErrorCallback());

        if (mCameraDevice == null) {
            Log.e(TAG, "Failed to open camera:" + mCameraId + ", aborting.");
            return;
        }
        mParameters = mCameraDevice.getParameters();
        initializeCapabilities();
        CameraInfo info = CameraHolder.instance().getCameraInfo()[mCameraId];
        mMirror = (info.facing == CameraInfo.CAMERA_FACING_FRONT);
        mFocusManager.setMirror(mMirror);
        mFocusManager.setParameters(mInitialParams);
        setupPreview();
        /*SPRD: Add for ZSL HDR and FREEZE @{ */
        sFreezeFrameControl.proxySharedPreferenceChanged();
        //mHDRController.proxyResetSwitcherEnforcement(mPreferences, mParameters);
        mUI.enableSwitchCameraButton(true);//add by sprd for bug456
        mZSLController.proxyResetSwitcherEnforcement(
                mPreferences, mParameters, isHdrOn());
        /* @} */

        // reset zoom value index
//        mZoomValue = 0;
        openCameraCommon();

        // Start switch camera animation. Post a message because
        // onFrameAvailable from the old camera may already exist.
        //mHandler.sendEmptyMessage(SWITCH_CAMERA_START_ANIMATION);
    }

    protected void setCameraId(int cameraId) {
        ListPreference pref = mPreferenceGroup.findPreference(CameraSettings.KEY_CAMERA_ID);
        pref.setValue("" + cameraId);
    }

    // either open a new camera or switch cameras
    private void openCameraCommon() {
        loadCameraPreferences();

        mUI.onCameraOpened(mPreferenceGroup, mPreferences, mParameters, this);
        if (mIsImageCaptureIntent) {
            mUI.overrideSettings(CameraSettings.KEY_CAMERA_HDR_PLUS,
                    mActivity.getString(R.string.setting_off_value));
        }
        //orig
        //updateSceneMode();
        updateSettingsMutex();
        showTapToFocusToastIfNeeded();
    }

    @Override
    public void onPreviewRectChanged(Rect previewRect) {
        if (mFocusManager != null) mFocusManager.setPreviewRect(previewRect);
    }

    private void resetExposureCompensation() {
        String value = mPreferences.getString(CameraSettings.KEY_EXPOSURE,
                CameraSettings.EXPOSURE_DEFAULT_VALUE);
        if (!CameraSettings.EXPOSURE_DEFAULT_VALUE.equals(value)) {
            Editor editor = mPreferences.edit();
            editor.putString(CameraSettings.KEY_EXPOSURE, "0");
            editor.apply();
        }
    }

    private void keepMediaProviderInstance() {
        // We want to keep a reference to MediaProvider in camera's lifecycle.
        // TODO: Utilize mMediaProviderClient instance to replace
        // ContentResolver calls.
        if (mMediaProviderClient == null) {
            mMediaProviderClient = mContentResolver
                    .acquireContentProviderClient(MediaStore.AUTHORITY);
        }
    }

    // Snapshots can only be taken after this is called. It should be called
    // once only. We could have done these things in onCreate() but we want to
    // make preview screen appear as soon as possible.
    private void initializeFirstTime() {
        if (mFirstTimeInitialized || mPaused) {
            return;
        }

        // Initialize location service.
        boolean recordLocation = RecordLocationPreference.get(
                mPreferences, mContentResolver);
        mLocationManager.recordLocation(recordLocation);

        keepMediaProviderInstance();

        mUI.initializeFirstTime();
        MediaSaveService s = mActivity.getMediaSaveService();
        // We set the listener only when both service and shutterbutton
        // are initialized.
        if (s != null) {
            s.setListener(this);
        }

        mNamedImages = new NamedImages();

        mFirstTimeInitialized = true;
        addIdleHandler();
        /* SPRD: Initialize ZSL controller */
        if (mZSLController != null) {
            mZSLController.proxyResetSwitcherValue(mPreferences);
        }
        mActivity.updateStorageSpaceAndHint();
    }

    // If the activity is paused and resumed, this method will be called in
    // onResume.
    private void initializeSecondTime() {
        // Start location update if needed.
        boolean recordLocation = RecordLocationPreference.get(
                mPreferences, mContentResolver);
        mLocationManager.recordLocation(recordLocation);
        MediaSaveService s = mActivity.getMediaSaveService();
        if (s != null) {
            s.setListener(this);
        }
        mNamedImages = new NamedImages();
        mUI.initializeSecondTime(mParameters);
        keepMediaProviderInstance();

        /* SPRD: Add for ZSL @{*/
        if (mZSLController != null) {
            mZSLController.proxyResetSwitcherValue(mPreferences);
        }
        /* @} */
    }

    private void showTapToFocusToastIfNeeded() {
        // Show the tap to focus toast if this is the first start.
        if (mFocusAreaSupported &&
                mPreferences.getBoolean(CameraSettings.KEY_CAMERA_FIRST_USE_HINT_SHOWN, true)
                // SPRD: AOB, check current is camera preview state
                && (mActivity != null && mActivity.proxyIsCameraPreview())) {
            // Delay the toast for one second to wait for orientation.
            mHandler.sendEmptyMessageDelayed(SHOW_TAP_TO_FOCUS_TOAST, 1000);
        }
    }

    private void addIdleHandler() {
        MessageQueue queue = Looper.myQueue();
        queue.addIdleHandler(new MessageQueue.IdleHandler() {
            @Override
            public boolean queueIdle() {
                Storage.ensureOSXCompatible();
                return false;
            }
        });
    }

    @Override
    public void startFaceDetection() {
        if (mFaceDetectionStarted) return;
        if (mParameters.getMaxNumDetectedFaces() > 0) {
            mFaceDetectionStarted = true;
            CameraInfo info = CameraHolder.instance().getCameraInfo()[mCameraId];
            mUI.onStartFaceDetection(mDisplayOrientation,
                    (info.facing == CameraInfo.CAMERA_FACING_FRONT));
            mCameraDevice.setFaceDetectionCallback(mHandler, mUI);
            mCameraDevice.startFaceDetection();
        }
    }

    @Override
    public void stopFaceDetection() {
        if (!mFaceDetectionStarted) return;
        if (mParameters.getMaxNumDetectedFaces() > 0) {
            mFaceDetectionStarted = false;
            mCameraDevice.setFaceDetectionCallback(null, null);
            mCameraDevice.stopFaceDetection();
            mUI.clearFaces();
        }
    }

    private final class ShutterCallback
            implements CameraShutterCallback {

        private boolean mNeedsAnimation;

        public ShutterCallback(boolean needsAnimation) {
            mNeedsAnimation = needsAnimation;
        }

        @Override
        public void onShutter(CameraProxy camera) {
            mShutterCallbackTime = System.currentTimeMillis();
            mShutterLag = mShutterCallbackTime - mCaptureStartTime;
            Log.v(TAG, "mShutterLag = " + mShutterLag + "ms");
            if (mNeedsAnimation) {
                mActivity.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        animateAfterShutter();
                    }
                });
            }
        }
    }

    private final class PostViewPictureCallback
            implements CameraPictureCallback {
        @Override
        public void onPictureTaken(byte [] data, CameraProxy camera) {
            mPostViewPictureCallbackTime = System.currentTimeMillis();
            Log.v(TAG, "mShutterToPostViewCallbackTime = "
                    + (mPostViewPictureCallbackTime - mShutterCallbackTime)
                    + "ms");
        }
    }

    private final class RawPictureCallback
            implements CameraPictureCallback {
        @Override
        public void onPictureTaken(byte [] rawData, CameraProxy camera) {
            mRawPictureCallbackTime = System.currentTimeMillis();
            Log.v(TAG, "mShutterToRawCallbackTime = "
                    + (mRawPictureCallbackTime - mShutterCallbackTime) + "ms");
        }
    }

    private final class JpegPictureCallback
            implements CameraPictureCallback {
        Location mLocation;
        public JpegPictureCallback(Location loc) {
            mLocation = loc;
            Log.d(TAG, "JpegPictureCallback continuous capture count=" + mContinuousCaptureCount);
        }

        @Override
        public void onPictureTaken(final byte [] jpegData, CameraProxy camera) {
            mNamedImages.nameNewImage(mCaptureStartTime);
            // SPRD: HDR screen hint supported
            if (mUI != null) {
                mUI.enableHdrScreenHint(false, mPreferences);
            }
            if (mPaused || --mContinuousCaptureCount < 0) {
                return;
            }
            if (mIsImageCaptureIntent) {
                stopPreview();
            }

            ExifInterface exif = Exif.getExif(jpegData);
            int orientation = Exif.getOrientation(exif);
            if (!mIsImageCaptureIntent && mContinuousCaptureCount == 0) {
                mUI.animateCapture(jpegData, orientation, false);
            }
            // @{ SPRD: bug 262395 hide module switcher view be not expect hdr begin
            //showSwitcher();
            mUI.setSwipingEnabled(true);
            /* if (mSceneMode == CameraUtil.SCENE_MODE_HDR) {
                mUI.showSwitcher();
                mUI.setSwipingEnabled(true);
            } SPRD: hide module switcher view be not expect hdr end*/
            // Check this in advance of each shot so we don't add to shutter
            // latency. It's true that someone else could write to the SD card in
            // the mean time and fill it, but that could have happened between the
            // shutter press and saving the JPEG too.
            mActivity.updateStorageSpaceAndHint();

            mJpegPictureCallbackTime = System.currentTimeMillis();
            // If postview callback has arrived, the captured image is displayed
            // in postview callback. If not, the captured image is displayed in
            // raw picture callback.
            if (mPostViewPictureCallbackTime != 0) {
                mShutterToPictureDisplayedTime =
                        mPostViewPictureCallbackTime - mShutterCallbackTime;
                mPictureDisplayedToJpegCallbackTime =
                        mJpegPictureCallbackTime - mPostViewPictureCallbackTime;
            } else {
                mShutterToPictureDisplayedTime =
                        mRawPictureCallbackTime - mShutterCallbackTime;
                mPictureDisplayedToJpegCallbackTime =
                        mJpegPictureCallbackTime - mRawPictureCallbackTime;
            }
            Log.v(TAG, "mPictureDisplayedToJpegCallbackTime = "
                    + mPictureDisplayedToJpegCallbackTime + "ms");

            // @{ SPRD: bug 251198
            //if (mIsImageCaptureIntent) {
            //   sFreezeFrameControl.proxyRunLoadProxy(jpegData);
            //}// @}

            mFocusManager.updateFocusUI(); // Ensure focus indicator is hidden.
            /* @origin
            if (!mIsImageCaptureIntent) {
                setupPreview();
            }*/

            /* SPRD:Add for HDR ZSL  @{ */
            //if (mHDRController != null)
            //    mHDRController.proxyDismissWaiting();
            Log.v(TAG, "mContinuousCaptureCount = "+ mContinuousCaptureCount);
            if (!mIsImageCaptureIntent) {
                if ((mZSLController.switchOff() || isHdrOn()) && mContinuousCaptureCount <= 0) {
                    setupPreview();
                } else if (mZSLController.switchOn()) {
                    setCameraState(IDLE);
                    startPreview(CameraActivity.KEY_MODE_ZSL);
                } else {
                    // Camera HAL of some devices have a bug. Starting preview
                    // immediately after taking a picture will fail. Wait some
                    // time before starting the preview.
                    if (!isContinueTakePicture()) {
                        mHandler.sendEmptyMessageDelayed(SETUP_PREVIEW, 300);
                    }
                }
            }
            /* @} add for HDR ZSL end */

                // Calculate the width and the height of the jpeg.
            Size s = mParameters.getPictureSize();
            int width, height;
            if ((mJpegRotation + orientation) % 180 == 0) {
                width = s.width;
                height = s.height;
            } else {
                width = s.height;
                height = s.width;
            }
            NamedEntity name = mNamedImages.getNextNameEntity();
            String title = (name == null) ? null : name.title;
            long date = (name == null) ? -1 : name.date;
            // Handle debug mode outputs
            if (mDebugUri != null) {
                // If using a debug uri, save jpeg there.
                saveToDebugUri(jpegData);

                // Adjust the title of the debug image shown in mediastore.
                if (title != null) {
                    title = DEBUG_IMAGE_PREFIX + title;
                }
            }

            if (title == null) {
                Log.e(TAG, "Unbalanced name/data pair");
            } else {
                if (date == -1) date = mCaptureStartTime;
                if (mHeading >= 0) {
                    // heading direction has been updated by the sensor.
                    ExifTag directionRefTag = exif.buildTag(
                            ExifInterface.TAG_GPS_IMG_DIRECTION_REF,
                            ExifInterface.GpsTrackRef.MAGNETIC_DIRECTION);
                    ExifTag directionTag = exif.buildTag(
                            ExifInterface.TAG_GPS_IMG_DIRECTION,
                            new Rational(mHeading, 1));
                    exif.setTag(directionRefTag);
                    exif.setTag(directionTag);
                }
                mActivity.getMediaSaveService().addImage(
                    jpegData, title, date, mLocation, width, height,
                    orientation, exif, mOnMediaSavedListener, mContentResolver, CameraUtil.MODE_CAMERA);
            }

            // SPRD: If mIsImageCaptureIntent is true use freezeframe show picture
            if(mIsImageCaptureIntent) {
                mJpegImageData = jpegData;
                if(!mQuickCapture) {
                    sFreezeFrameControl.proxyAnimation(true);
                } else {
                    onCaptureDone();
                }
            } else {
                if (sFreezeFrameControl != null &&
                    sFreezeFrameControl.isFreezeFrame()) {
                    sFreezeFrameControl.proxyAnimation(true);
                }
                // Animate capture with real jpeg data instead of a preview frame.
            }

            if (mContinuousCaptureCount <=0 && !isContinueTakePicture()) {
                updateCameraControls();
                mIsTakingPicture = false;
            } else {
                mIsTakingPicture = true;
            }
            long now = System.currentTimeMillis();
            mJpegCallbackFinishTime = now - mJpegPictureCallbackTime;
            Log.v(TAG, "mJpegCallbackFinishTime = "
                    + mJpegCallbackFinishTime + "ms");
            mJpegPictureCallbackTime = 0;
        }
    }

    /* SPRD: Add for ZSL @{ */
    private void startPreview(int mode) {
        Log.d(TAG, "startPreview in ZSL mode");
        if (mPaused) {
            return;
        }

        mFocusManager.resetTouchFocus();
        mCameraDevice.setErrorCallback(mErrorCallback);

        setDisplayOrientation();
        mCameraDevice.setDisplayOrientation(mCameraDisplayOrientation);

        if (!mSnapshotOnIdle) {
            // If the focus mode is continuous autofocus, call cancelAutoFocus to
            // resume it because it may have been paused by autoFocus call.
            if (CameraUtil.FOCUS_MODE_CONTINUOUS_PICTURE.equals(mFocusManager.getFocusMode())) {
                mCameraDevice.cancelAutoFocus();
            }
            mFocusManager.setAeAwbLock(false); // Unlock AE and AWB.
        }
        setCameraParameters(UPDATE_PARAM_ALL);
        // Let UI set its expected aspect ratio

        mFocusManager.onPreviewStarted();

        if (mSnapshotOnIdle || mActivity.isAutoCapture()) {
            mHandler.post(mDoSnapRunnable);
        }
    }
    /* @} */

    private final class AutoFocusCallback implements CameraAFCallback {
        @Override
        public void onAutoFocus(
                boolean focused, CameraProxy camera) {
            if (mPaused) return;

            mAutoFocusTime = System.currentTimeMillis() - mFocusStartTime;
            Log.v(TAG, "mAutoFocusTime = " + mAutoFocusTime + "ms");
            setCameraState(IDLE);
            mFocusManager.onAutoFocus(focused, mUI.isShutterPressed());
        }
    }

    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
    private final class AutoFocusMoveCallback
            implements CameraAFMoveCallback {
        @Override
        public void onAutoFocusMoving(
                boolean moving, CameraProxy camera) {
            mFocusManager.onAutoFocusMoving(moving);
        }
    }

    /**
     * This class is just a thread-safe queue for name,date holder objects.
     */
    public static class NamedImages {
        private Vector<NamedEntity> mQueue;

        public NamedImages() {
            mQueue = new Vector<NamedEntity>();
        }

        public void nameNewImage(long date) {
            NamedEntity r = new NamedEntity();
            r.title = CameraUtil.createJpegName(date);
            r.date = date;
            mQueue.add(r);
        }

        public NamedEntity getNextNameEntity() {
            synchronized(mQueue) {
                if (!mQueue.isEmpty()) {
                    return mQueue.remove(0);
                }
            }
            return null;
        }

        public static class NamedEntity {
            public String title;
            public long date;
        }
    }

    private void setCameraState(int state) {
        mCameraState = state;
        switch (state) {
            case PhotoController.PREVIEW_STOPPED:
            case PhotoController.SNAPSHOT_IN_PROGRESS:
            case PhotoController.SWITCHING_CAMERA:
            case PhotoController.FOCUSING:
                mUI.enableGestures(false);
                break;
            case PhotoController.IDLE:
                mUI.enableGestures(true);
                break;
        }
    }

    private void animateAfterShutter() {
        // Only animate when in full screen capture mode
        // i.e. If monkey/a user swipes to the gallery during picture taking,
        // don't show animation
        // SPRD: remove animation from customer requirement
//        if (!mIsImageCaptureIntent) {
//            mUI.animateFlash();
//        }
    }

    @Override
    public boolean capture() {
        mEnableTopButton = false;
        // If we are already in the middle of taking a snapshot or the image save request
        // is full then ignore.
        if (mCameraDevice == null || mCameraState == SNAPSHOT_IN_PROGRESS
                || mCameraState == SWITCHING_CAMERA
                || mActivity.getMediaSaveService() == null
                || mActivity.getMediaSaveService().isQueueFull()) {
            Log.i(TAG, "Capture is rerurn !");
            return false;
        }
        mCaptureStartTime = System.currentTimeMillis();
        mPostViewPictureCallbackTime = 0;
        mJpegImageData = null;

        final boolean animateBefore = (mSceneMode == CameraUtil.SCENE_MODE_HDR);

        if (animateBefore) {
            animateAfterShutter();
        }

        // Set rotation and gps data.
        int orientation;
        // We need to be consistent with the framework orientation (i.e. the
        // orientation of the UI.) when the auto-rotate screen setting is on.
        if (mActivity.isAutoRotateScreen()) {
            orientation = (360 - mDisplayRotation) % 360;
        } else {
            orientation = mOrientation;
        }
        mJpegRotation = CameraUtil.getJpegRotation(mCameraId, orientation);
        mParameters.setRotation(mJpegRotation);
        Location loc = mLocationManager.getCurrentLocation();
        CameraUtil.setGpsParameters(mParameters, loc);
        mParameters.set(CameraSettings.KEY_CAPTURE_MODE, mContinuousCaptureCount);
        Log.v(TAG, "take pictrue starting  mParameters =" +mParameters.flatten());
        mCameraDevice.setParameters(mParameters);

        // We don't want user to press the button again while taking a
        // multi-second HDR photo.
        mUI.enableShutter(false);
        mCameraDevice.takePicture(mHandler,
                new ShutterCallback(!animateBefore),
                mRawPictureCallback, mPostViewPictureCallback,
                new JpegPictureCallback(loc));

        mNamedImages.nameNewImage(mCaptureStartTime);

        mFaceDetectionStarted = false;
        setCameraState(SNAPSHOT_IN_PROGRESS);
        UsageStatistics.onEvent(UsageStatistics.COMPONENT_CAMERA,
                UsageStatistics.ACTION_CAPTURE_DONE, "Photo", 0,
                UsageStatistics.hashFileName(mNamedImages.mQueue.lastElement().title + ".jpg"));
        return true;
    }

    @Override
    public void setFocusParameters() {
        setCameraParameters(UPDATE_PARAM_PREFERENCE);
    }

    private int getPreferredCameraId(ComboPreferences preferences) {
        int intentCameraId = CameraUtil.getCameraFacingIntentExtras(mActivity);
        if (intentCameraId != -1) {
            // Testing purpose. Launch a specific camera through the intent
            // extras.
            return intentCameraId;
        } else {
            return CameraSettings.readPreferredCameraId(preferences);
        }
    }

    private void updateSceneMode() {
        // If scene mode is set, we cannot set flash mode, white balance, and
        // focus mode, instead, we read it from driver
        if (!Parameters.SCENE_MODE_AUTO.equals(mSceneMode)) {
            overrideCameraSettings(mParameters.getFlashMode(),
                    mParameters.getWhiteBalance(), mParameters.getFocusMode());
        } else {
            overrideCameraSettings(null, null, null);
        }
    }

    private void overrideCameraSettings(final String flashMode,
                                        final String whiteBalance, final String focusMode) {
        mUI.overrideSettings(
                CameraSettings.KEY_FLASH_MODE, flashMode,
                CameraSettings.KEY_WHITE_BALANCE, whiteBalance,
                CameraSettings.KEY_FOCUS_MODE, focusMode);
    }

    /*
     * SPRD: added 20140109 of 256391 HDR, SceneMode Setting Mutex @{
     * Describe:
     *   Use a Bit-like array named overrideIndex to describe the
     * mutex macro, one setting respond to one bit.
     *   Use a String... array named
     * overrideItem to describe the mutex Settings key-value.
     *   Attention, overrideItem length must equal the macro sum * 2, no less, no more.
     *   Attention, override value comes from mPreferences, and the current hardware value is the default one.
     */
    @Override
    public void updateSettingsMutex() {
        // define the mutex macro
        int len = 0;
        int WHITE_BALANCE = 1 << (len++);
        int FLASH_MODE = 1 << (len++);
        int FOCUS_MODE = 1 << (len++);
        int EXPOSURE = 1 << (len++);
        int SCENE_MODE = 1 << (len++);
        int PICTURE_SIZE = 1 << (len++);
        int CAMERA_VIDEO_ZSL = 1 << (len++);
        int CAMERA_CONTINUOUS_CAPTURE = 1 << (len++);

        String overrideItem[] = new String[len * 2];

        // define overrideIndex
        int overrideIndex = 0;

        if (!Parameters.SCENE_MODE_AUTO.equals(mSceneMode)) {
            overrideIndex |= WHITE_BALANCE;
            overrideIndex |= FLASH_MODE;
            overrideIndex |= FOCUS_MODE;
        }

        if (Parameters.SCENE_MODE_HDR.equals(mSceneMode)) {
            overrideIndex |= WHITE_BALANCE;
            overrideIndex |= EXPOSURE;
            overrideIndex |= SCENE_MODE;
            overrideIndex |= PICTURE_SIZE;
            overrideIndex |= CAMERA_VIDEO_ZSL;
            overrideIndex |= CAMERA_CONTINUOUS_CAPTURE;
        }
        Log.d(TAG, "overrideIndex = " + overrideIndex);

        // define overrideItem
        int index = 0;
        overrideItem[index++] = CameraSettings.KEY_WHITE_BALANCE;
        if ((WHITE_BALANCE & overrideIndex) == WHITE_BALANCE) {
            overrideItem[index++] = mPreferences.getString(
                    CameraSettings.KEY_WHITE_BALANCE, Parameters.WHITE_BALANCE_AUTO);
            boolean supported = isSupported(Parameters.WHITE_BALANCE_AUTO,
                    mParameters.getSupportedWhiteBalance());
            if (supported) {
                mParameters.setWhiteBalance(Parameters.WHITE_BALANCE_AUTO);
            }
        } else {
            overrideItem[index++] = null;
        }

        overrideItem[index++] = CameraSettings.KEY_FLASH_MODE;
        if ((FLASH_MODE & overrideIndex) == FLASH_MODE) {
            overrideItem[index++] = mPreferences.getString(
                    CameraSettings.KEY_FLASH_MODE, Parameters.FLASH_MODE_OFF);
            boolean supported = CameraSettings.VALUE_TRUE.equals(
                    mParameters.get(CameraSettings.KEY_HAL_FLASH_SUPPORTED));
            if (supported) {
                mParameters.setFlashMode(Parameters.FLASH_MODE_OFF);
            }
        } else {
            overrideItem[index++] = null;
        }

        overrideItem[index++] = CameraSettings.KEY_FOCUS_MODE;
        if ((FOCUS_MODE & overrideIndex) == FOCUS_MODE) {
            overrideItem[index++] = mPreferences.getString(
                    CameraSettings.KEY_FOCUS_MODE, Parameters.FOCUS_MODE_AUTO);
            boolean supported = isSupported(Parameters.FOCUS_MODE_AUTO,
                    mParameters.getSupportedFocusModes());
            if (supported) {
                mParameters.setFocusMode(Parameters.FOCUS_MODE_AUTO);
            }
        } else {
            overrideItem[index++] = null;
        }

        overrideItem[index++] = CameraSettings.KEY_EXPOSURE;
        if ((EXPOSURE & overrideIndex) == EXPOSURE) {
            overrideItem[index++] = mPreferences.getString(
                    CameraSettings.KEY_EXPOSURE, "0");
            mParameters.setExposureCompensation(0);
        } else {
            overrideItem[index++] = null;
        }

        overrideItem[index++] = CameraSettings.KEY_SCENE_MODE;
        if ((SCENE_MODE & overrideIndex) == SCENE_MODE) {
            overrideItem[index++] = mPreferences.getString(
                    CameraSettings.KEY_SCENE_MODE, Parameters.SCENE_MODE_AUTO);
            mParameters.setSceneMode(Parameters.SCENE_MODE_HDR);
        } else {
            overrideItem[index++] = null;
        }

        overrideItem[index++] = CameraSettings.KEY_PICTURE_SIZE;
        if ((PICTURE_SIZE & overrideIndex) == PICTURE_SIZE) {
            overrideItem[index++] = mPreferences.getString(
                    CameraSettings.KEY_PICTURE_SIZE, null);
        } else {
            overrideItem[index++] = null;
        }

        overrideItem[index++] = CameraSettings.KEY_CAMERA_VIDEO_ZSL;
        if ((CAMERA_VIDEO_ZSL & overrideIndex) == CAMERA_VIDEO_ZSL) {
            overrideItem[index++] = mPreferences.getString(
                    CameraSettings.KEY_CAMERA_VIDEO_ZSL, CameraSettings.VALUE_OFF);
        } else {
            overrideItem[index++] = null;
        }

        overrideItem[index++] = CameraSettings.KEY_CAMERA_CONTINUOUS_CAPTURE;
        if ((CAMERA_CONTINUOUS_CAPTURE & overrideIndex) == CAMERA_CONTINUOUS_CAPTURE) {
            overrideItem[index++] = mPreferences.getString(
                    CameraSettings.KEY_CAMERA_CONTINUOUS_CAPTURE, "1");
//            mParameters.set(CameraSettings.KEY_CAPTURE_MODE, "1");
        } else {
            overrideItem[index++] = null;
        }

        mUI.overrideSettings(overrideItem);
        /* Bug 267440 ANR @{ */
        if (overrideIndex != 0 && mCameraDevice != null) {
            mCameraDevice.setParameters(mParameters);
        }
        /* @{ */
    }

    /* @} */

    private void loadCameraPreferences() {
        CameraSettings settings = new CameraSettings(mActivity, mInitialParams,
                mCameraId, CameraHolder.instance().getCameraInfo());
        mPreferenceGroup = settings.getPreferenceGroup(R.xml.camera_preferences);
    }

    @Override
    public void onOrientationChanged(int orientation) {
        // We keep the last known orientation. So if the user first orient
        // the camera then point the camera to floor or sky, we still have
        // the correct orientation.
        if (orientation == OrientationEventListener.ORIENTATION_UNKNOWN) return;
        mOrientation = CameraUtil.roundOrientation(orientation, mOrientation);
        /* @{ SPRD: fix bug 255774 start */
        // When the screen is unlocked, display rotation may change. Always
        // calculate the up-to-date orientationCompensation.
        int orientationCompensation = mOrientation
                + CameraUtil.getDisplayRotation(mActivity) % 360;
        if (mOrientationCompensation != orientationCompensation) {
            mOrientationCompensation = orientationCompensation;
        }
        /* fix bug 255774 end @}*/

        // Show the toast after getting the first orientation changed.
        if (mHandler.hasMessages(SHOW_TAP_TO_FOCUS_TOAST)) {
            mHandler.removeMessages(SHOW_TAP_TO_FOCUS_TOAST);
            showTapToFocusToast();
        }
    }

    @Override
    public void onStop() {
        if (mMediaProviderClient != null) {
            mMediaProviderClient.release();
            mMediaProviderClient = null;
        }
    }

    @Override
    public void onCaptureCancelled() {
        mActivity.setResultEx(Activity.RESULT_CANCELED, new Intent());
        mActivity.finish();
    }

    @Override
    public void onCaptureRetake() {
        if (mPaused)
            return;
        /* @{ SPRD: bug 251198 start */
        mJpegImageData = null;
        /* bug 251198 end @} */
        mUI.hidePostCaptureAlert();
        setupPreview();
    }

    @Override
    public void onCaptureDone() {
        if (mPaused) {
            return;
        }

        byte[] data = mJpegImageData;

        if (mCropValue == null) {
            // First handle the no crop case -- just return the value.  If the
            // caller specifies a "save uri" then write the data to its
            // stream. Otherwise, pass back a scaled down version of the bitmap
            // directly in the extras.
            if (mSaveUri != null) {
                OutputStream outputStream = null;
                try {
                    outputStream = mContentResolver.openOutputStream(mSaveUri);
                    if (outputStream != null) {
                        outputStream.write(data);
                        outputStream.close();
                    }

                    mActivity.setResultEx(Activity.RESULT_OK);
                    mActivity.finish();
                } catch (IOException ex) {
                    // ignore exception
                } finally {
                    CameraUtil.closeSilently(outputStream);
                }
            } else {
                ExifInterface exif = Exif.getExif(data);
                int orientation = Exif.getOrientation(exif);
                Bitmap bitmap = CameraUtil.makeBitmap(data, 50 * 1024);
                bitmap = CameraUtil.rotate(bitmap, orientation);
                mActivity.setResultEx(Activity.RESULT_OK,
                        new Intent("inline-data").putExtra("data", bitmap));
                mActivity.finish();
            }
        } else {
            // Save the image to a temp file and invoke the cropper
            Uri tempUri = null;
            FileOutputStream tempStream = null;
            try {
                File path = mActivity.getFileStreamPath(sTempCropFilename);
                path.delete();
                tempStream = mActivity.openFileOutput(sTempCropFilename, 0);
                tempStream.write(data);
                tempStream.close();
                tempUri = Uri.fromFile(path);
            } catch (FileNotFoundException ex) {
                mActivity.setResultEx(Activity.RESULT_CANCELED);
                mActivity.finish();
                return;
            } catch (IOException ex) {
                mActivity.setResultEx(Activity.RESULT_CANCELED);
                mActivity.finish();
                return;
            } finally {
                CameraUtil.closeSilently(tempStream);
            }

            Bundle newExtras = new Bundle();
            if (mCropValue.equals("circle")) {
                newExtras.putString("circleCrop", "true");
            }
            if (mSaveUri != null) {
                newExtras.putParcelable(MediaStore.EXTRA_OUTPUT, mSaveUri);
            } else {
                newExtras.putBoolean(CameraUtil.KEY_RETURN_DATA, true);
            }
            if (mActivity.isSecureCamera()) {
                newExtras.putBoolean(CameraUtil.KEY_SHOW_WHEN_LOCKED, true);
            }

            /* @{ SPRD: bug 251198 start */
            mJpegImageData = null;
            /* bug 251198 end @} */

            // TODO: Share this constant.
            final String CROP_ACTION = "com.android.camera.action.CROP";
            Intent cropIntent = new Intent(CROP_ACTION);

            cropIntent.setData(tempUri);
            cropIntent.putExtras(newExtras);

            mActivity.startActivityForResult(cropIntent, REQUEST_CROP);
        }
    }

    @Override
    public void onShutterButtonFocus(boolean pressed) {
        if (mPaused || mUI.collapseCameraControls()
                || (mCameraState == SNAPSHOT_IN_PROGRESS)
                || (mCameraState == PREVIEW_STOPPED)) return;

        // Do not do focus if there is not enough storage.
        if (pressed && !canTakePicture()) return;

        if (pressed) {
            mFocusManager.onShutterDown();
        } else {
            // for countdown mode, we need to postpone the shutter release
            // i.e. lock the focus during countdown.
            if (!mUI.isCountingDown()) {
                mFocusManager.onShutterUp();
            }
        }
    }

    @Override
    public void onShutterButtonClick() {
        if (mPaused || mUI.collapseCameraControls()
                || (mCameraState == SWITCHING_CAMERA)
                || (mCameraState == PREVIEW_STOPPED)
                || isFreezeFrameDisplay()
                || mActivity.getMediaSaveService() == null
                || mActivity.getMediaSaveService().isQueueFull()) {
            Log.d(TAG, "onShutterButtonClick is return !");
            return;
        }

        // Do not take the picture if there is not enough storage.
        if (mActivity.getStorageSpaceBytes() <= Storage.LOW_STORAGE_THRESHOLD_BYTES) {
            Log.i(TAG, "Not enough space or storage not ready. remaining="
                    + mActivity.getStorageSpaceBytes());
            return;
        }
        Log.v(TAG, "onShutterButtonClick: mCameraState=" + mCameraState);

        /* SPRD: fixbug262369 set invisible of thumbnailview in freezeFrame  @{ */
        if (sFreezeFrameControl != null && sFreezeFrameControl.isFreezeFrame()) {
            mUI.setPreviewThumbVisibility(View.INVISIBLE);
        }
        if (mContinuousCaptureCount <= 0) {
            mContinuousCaptureCount = getContinuousCount();
        } else if (mIsTakingPicture) {
            Log.v(TAG, "Taking picture   mContinueTakePictureCount =" + mContinueTakePictureCount);
            return;
        }
        Log.v(TAG, " onShutterButtonClick  mContinueTakePictureCount =" + mContinueTakePictureCount);

        mUI.hideControlTopButton();
        /*  @}  */
        // @{ SPRD: bug 261395 hide module switcher view be not expect hdr begin
        hideSwitcher();
        // SPRD: bug 260858
        mEnableCameraSet = false;
        mUI.hideControlsUI();
        mUI.setSwipingEnabled(false);
        /* if (mSceneMode == CameraUtil.SCENE_MODE_HDR) {
            mUI.hideSwitcher();
            mUI.setSwipingEnabled(false);
        } SPRD: hide module switcher view be not expect hdr @}*/
        // If the user wants to do a snapshot while the previous one is still
        // in progress, remember the fact and do it after we finish the previous
        // one and re-start the preview. Snapshot in progress also includes the
        // state that autofocus is focusing and a picture will be taken when
        // focus callback arrives.
        if ((mFocusManager.isFocusingSnapOnFinish() || mCameraState == SNAPSHOT_IN_PROGRESS)
                && !mIsImageCaptureIntent) {
            mSnapshotOnIdle = true;
            return;
        }

        String timer = mPreferences.getString(
                CameraSettings.KEY_TIMER,
                mActivity.getString(R.string.pref_camera_timer_default));
        boolean playSound = mPreferences.getString(CameraSettings.KEY_TIMER_SOUND_EFFECTS,
                mActivity.getString(R.string.pref_camera_timer_sound_default))
                .equals(mActivity.getString(R.string.setting_on_value));

        int seconds = Integer.parseInt(timer);
        // When shutter button is pressed, check whether the previous countdown is
        // finished. If not, cancel the previous countdown and start a new one.
        if (mUI.isCountingDown()) {
            mUI.cancelCountDown();
        }
        Log.d(TAG, "  mIsTakingPicture = " + mIsTakingPicture + "   mContinuousCaptureCount="
                + mContinuousCaptureCount);
        mUI.enableShutter(false);
        if (seconds > 0) {
            mUI.startCountDown(seconds, playSound);
        } else {
            mSnapshotOnIdle = false;
            mFocusManager.doSnap();
            // SPRD: HDR screen hint supported
            if (mUI != null) {
                mUI.enableHdrScreenHint(true, mPreferences);
            }
            if (mUI != null && isContinueTakePicture()) {
                mUI.enableBurstScreenHint(true);
            }
        }
    }

    @Override
    public void installIntentFilter() {
        // Do nothing.
    }

    @Override
    public boolean updateStorageHintOnResume() {
        return mFirstTimeInitialized;
    }

    public void updateCameraAppView() {
        //mActivity.updateCameraAppView();//SPRD:Add for freeze_display
    }

    @Override
    public void onResumeBeforeSuper() {
        mPaused = false;
    }

    private boolean prepareCamera() {
        // We need to check whether the activity is paused before long
        // operations to ensure that onPause() can be done ASAP.
        Log.v(TAG, "Open camera device.");
        mCameraDevice = CameraUtil.openCamera(
                mActivity, mCameraId, mHandler,
                mActivity.getCameraOpenErrorCallback());
        if (mCameraDevice == null) {
            Log.e(TAG, "Failed to open camera:" + mCameraId);
            mHandler.sendEmptyMessage(OPEN_CAMERA_FAIL);
            return false;
        }
        mParameters = mCameraDevice.getParameters();

        initializeCapabilities();
        if (mFocusManager == null) initializeFocusManager();
        setCameraParameters(UPDATE_PARAM_ALL);
        mHandler.sendEmptyMessage(CAMERA_OPEN_DONE);
        mCameraPreviewParamsReady = true;
        startPreview();
        mOnResumeTime = SystemClock.uptimeMillis();
        checkDisplayRotation();
        return true;
    }

    @Override
    public void onResumeAfterSuper() {
        // Add delay on resume from lock screen only, in order to to speed up
        // the onResume --> onPause --> onResume cycle from lock screen.
        // Don't do always because letting go of thread can cause delay.
        String action = mActivity.getIntent().getAction();
        if (MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA.equals(action)
                || MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE.equals(action)) {
            Log.v(TAG, "On resume, from lock screen.");
            // Note: onPauseAfterSuper() will delete this runnable, so we will
            // at most have 1 copy queued up.
            mHandler.postDelayed(new Runnable() {
                public void run() {
                    onResumeTasks();
                }
            }, ON_RESUME_TASKS_DELAY_MSEC);
        } else {
            Log.v(TAG, "On rmEnableTopButtonesume.");
            onResumeTasks();
        }
        /* @{ SPRD: fix bug 272810 start */
        mEnableTopButton = true;
        /* end }@ */
        mEnableCameraSet = true;
        // SPRD: Camera HAL is restarted , continuous is reset.
        mContinuousCaptureCount = 0;
    }

    private void onResumeTasks() {
        Log.v(TAG, "Executing onResumeTasks.");
        if (mOpenCameraFail || mCameraDisabled) return;

        mJpegPictureCallbackTime = 0;
        mZoomValue = 0;
        resetExposureCompensation();
        if (!prepareCamera()) {
            // Camera failure.
            return;
        }

        // If first time initialization is not finished, put it in the
        // message queue.
        if (!mFirstTimeInitialized) {
            mHandler.sendEmptyMessage(FIRST_TIME_INIT);
        } else {
            initializeSecondTime();
        }
        mUI.initDisplayChangeListener();
        keepScreenOnAwhile();
        mUI.hidePreviewCover();

        UsageStatistics.onContentViewChanged(
                UsageStatistics.COMPONENT_CAMERA, "PhotoModule");

        Sensor gsensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
        if (gsensor != null) {
            mSensorManager.registerListener(this, gsensor, SensorManager.SENSOR_DELAY_NORMAL);
        }

        Sensor msensor = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
        if (msensor != null) {
            mSensorManager.registerListener(this, msensor, SensorManager.SENSOR_DELAY_NORMAL);
        }

    }

    @Override
    public void onPauseBeforeSuper() {
        mPaused = true;
        Sensor gsensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
        if (gsensor != null) {
            mSensorManager.unregisterListener(this, gsensor);
        }

        Sensor msensor = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
        if (msensor != null) {
            mSensorManager.unregisterListener(this, msensor);
        }

        // SPRD: HDR screen hint supported
        if (mUI != null) {
            mUI.enableHdrScreenHint(false, mPreferences);
            mUI.enableBurstScreenHint(false);
        }
        /* SPRD bug294204 */
        if (mCameraState == SNAPSHOT_IN_PROGRESS || mIsTakingPicture) {
            mIsTakingPicture = false;
        }
    }

    @Override
    public void onPauseAfterSuper() {
        Log.v(TAG, "On pause.");
        // SPRD: Disable preview cover for preformance.
        // mUI.showPreviewCover();

        // Reset the focus first. Camera CTS does not guarantee that
        // cancelAutoFocus is allowed after preview stops.
        if (mCameraDevice != null && mCameraState != PREVIEW_STOPPED) {
            mCameraDevice.cancelAutoFocus();
        }
        // If the camera has not been opened asynchronously yet,
        // and startPreview hasn't been called, then this is a no-op.
        // (e.g. onResume -> onPause -> onResume).
        stopPreview();

        mNamedImages = null;

        if (mLocationManager != null) mLocationManager.recordLocation(false);

        // If we are in an image capture intent and has taken
        // a picture, we just clear it in onPause.
        /* @{ SPRD: bug 251198 start */
        //mJpegImageData = null;
        /* bug 251198 end @} */

        // Remove the messages and runnables in the queue.
        mHandler.removeCallbacksAndMessages(null);

        closeCamera();

        resetScreenOn();
        mUI.onPause();

        mPendingSwitchCameraId = -1;
        if (mFocusManager != null) mFocusManager.removeMessages();
        MediaSaveService s = mActivity.getMediaSaveService();
        if (s != null) {
            s.setListener(null);
        }
        mUI.removeDisplayChangeListener();
    }

    /**
     * The focus manager is the first UI related element to get initialized,
     * and it requires the RenderOverlay, so initialize it here
     */
    private void initializeFocusManager() {
        // Create FocusManager object. startPreview needs it.
        // if mFocusManager not null, reuse it
        // otherwise create a new instance
        if (mFocusManager != null) {
            mFocusManager.removeMessages();
        } else {
            CameraInfo info = CameraHolder.instance().getCameraInfo()[mCameraId];
            mMirror = (info.facing == CameraInfo.CAMERA_FACING_FRONT);
            String[] defaultFocusModes = mActivity.getResources().getStringArray(
                    R.array.pref_camera_focusmode_default_array);
            mFocusManager = new FocusOverlayManager(mPreferences, defaultFocusModes,
                    mInitialParams, this, mMirror,
                    mActivity.getMainLooper(), mUI);
        }
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        Log.v(TAG, "onConfigurationChanged");
        mUI.setShutterButtonRes(newConfig.orientation);
        if (mFocusManager != null) {
            mFocusManager.resetTouchFocus();
        }
        setDisplayOrientation();
        // SPRD: Update freezeFrame display when change screen configuration
        if(sFreezeFrameControl !=null && sFreezeFrameControl.mFreezeVisible)
            sFreezeFrameControl.updateFreezeUi();
    }

    @Override
    public void updateCameraOrientation() {
        if (mDisplayRotation != CameraUtil.getDisplayRotation(mActivity)) {
            setDisplayOrientation();
            // SPRD: Update freezeFrame display when camera orientation change
            if(sFreezeFrameControl !=null && sFreezeFrameControl.mFreezeVisible)
                sFreezeFrameControl.updateFreezeUi();
        }
    }

    @Override
    public void onActivityResult(
            int requestCode, int resultCode, Intent data) {
        switch (requestCode) {
            case REQUEST_CROP: {
                Intent intent = new Intent();
                if (data != null) {
                    Bundle extras = data.getExtras();
                    if (extras != null) {
                        intent.putExtras(extras);
                    }
                }
                mActivity.setResultEx(resultCode, intent);
                mActivity.finish();

                File path = mActivity.getFileStreamPath(sTempCropFilename);
                path.delete();

                break;
            }
        }
    }

    private boolean canTakePicture() {
        return isCameraIdle() && (mActivity.getStorageSpaceBytes() > Storage.LOW_STORAGE_THRESHOLD_BYTES);
    }

    @Override
    public void autoFocus() {
        // SPRD :Modified this because this will cause camera focus state wrong.
        setCameraState(FOCUSING);
        mFocusStartTime = System.currentTimeMillis();
        mCameraDevice.autoFocus(mHandler, mAutoFocusCallback);
        // setCameraState(FOCUSING);
    }

    @Override
    public void cancelAutoFocus() {
        mCameraDevice.cancelAutoFocus();
        setCameraState(IDLE);
        setCameraParameters(UPDATE_PARAM_PREFERENCE);
    }

    // Preview area is touched. Handle touch focus.
    @Override
    public void onSingleTapUp(View view, int x, int y) {
        if (mPaused || mCameraDevice == null || !mFirstTimeInitialized
                || mCameraState == SNAPSHOT_IN_PROGRESS
                || mCameraState == SWITCHING_CAMERA
                || mCameraState == PREVIEW_STOPPED
                || sFreezeFrameControl.mFreezeVisible) {
            return;
        }

        // Check if metering area or focus area is supported.
        if (!mFocusAreaSupported && !mMeteringAreaSupported) return;
        mFocusManager.onSingleTapUp(x, y);
    }

    @Override
    public boolean onBackPressed() {
        return mUI.onBackPressed();
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        switch (keyCode) {
/*            edit by topwise houyi for bug 190
 * 			case KeyEvent.KEYCODE_VOLUME_UP:
            case KeyEvent.KEYCODE_VOLUME_DOWN:
*/            case KeyEvent.KEYCODE_FOCUS:
                if (/*TODO: mActivity.isInCameraApp() &&*/ mFirstTimeInitialized) {
                    // SPRD: Freeze display don't action the key_down event
                    if(sFreezeFrameControl != null &&
                            sFreezeFrameControl.mFreezeVisible) {
                        return true;
                    }
                    if (event.getRepeatCount() == 0) {
                        onShutterButtonFocus(true);
                    }
                    return true;
                }
                return false;
            case KeyEvent.KEYCODE_CAMERA:
                // SPRD: Freeze display don't action the key_down event
                if(sFreezeFrameControl != null &&
                        sFreezeFrameControl.mFreezeVisible) {
                    return true;
                }
                if (mCameraState == SNAPSHOT_IN_PROGRESS || mIsTakingPicture) {
                    Log.e(TAG,"Press KEYCODE_CAMERA down,SNAPSHOT_IN_PROGRESS & isCountingDown, So Direct Return.");
                    return true;
                }
                if (mFirstTimeInitialized && event.getRepeatCount() == 0) {
                    onShutterButtonFocus(true);
                }
                return true;
            case KeyEvent.KEYCODE_DPAD_CENTER:
                // If we get a dpad center event without any focused view, move
                // the focus to the shutter button and press it.
                if (mFirstTimeInitialized && event.getRepeatCount() == 0) {
                    // Start auto-focus immediately to reduce shutter lag. After
                    // the shutter button gets the focus, onShutterButtonFocus()
                    // will be called again but it is fine.
                    onShutterButtonFocus(true);
                    mUI.pressShutterButton();
                }
                return true;
        }
        return false;
    }

    @Override
    public boolean onKeyUp(int keyCode, KeyEvent event) {
        switch (keyCode) {
        		//edit by topwise houyi for bug 190
/*            case KeyEvent.KEYCODE_VOLUME_UP:
            case KeyEvent.KEYCODE_VOLUME_DOWN:
                if (mActivity.isInCameraApp() &&  mFirstTimeInitialized) {
                    // SPRD: Freeze display don't action the key_up event
                    if(sFreezeFrameControl != null &&
                            sFreezeFrameControl.mFreezeVisible) {
                        return true;
                    }
                    if (getCameraState() == SNAPSHOT_IN_PROGRESS || mIsTakingPicture) {
                        Log.e(TAG,"onKeyUp SNAPSHOT_IN_PROGRESS, So Direct Return.");
                        return true;
                    }
                    onShutterButtonClick();
                    return true;
                }
                return false;
*/            case KeyEvent.KEYCODE_FOCUS:
                if (mFirstTimeInitialized) {
                    // SPRD: Freeze display don't action the key_up event
                    if(sFreezeFrameControl != null &&
                            sFreezeFrameControl.mFreezeVisible) {
                        return true;
                    }
                    onShutterButtonFocus(false);
                }
                return true;
            case KeyEvent.KEYCODE_CAMERA:
                if (mFirstTimeInitialized) {
                    if (mCameraState == SNAPSHOT_IN_PROGRESS || mIsTakingPicture) {
                        Log.e(TAG,"Press KEYCODE_CAMERA up,SNAPSHOT_IN_PROGRESS or isCountingDown, So Direct Return.");
                        return true;
                    }
                    if(sFreezeFrameControl != null && sFreezeFrameControl.mFreezeVisible) {
                        return true;
                    }
                    onShutterButtonClick();
                    return true;
                }
                return false;
        }
        return false;
    }

    private void closeCamera() {
        Log.v(TAG, "Close camera device.");
        if (mCameraDevice != null) {
            mCameraDevice.setZoomChangeListener(null);
            mCameraDevice.setFaceDetectionCallback(null, null);
            mCameraDevice.setErrorCallback(null);

            if (mActivity.isSecureCamera() && !CameraActivity.isFirstStartAfterScreenOn()) {
                // Blocks until camera is actually released.
                CameraHolder.instance().strongRelease();
            } else {
                CameraHolder.instance().release();
            }

            mFaceDetectionStarted = false;
            mCameraDevice = null;
            setCameraState(PREVIEW_STOPPED);
            mFocusManager.onCameraReleased();
        }
    }

    private void setDisplayOrientation() {
        mDisplayRotation = CameraUtil.getDisplayRotation(mActivity);
        mDisplayOrientation = CameraUtil.getDisplayOrientation(mDisplayRotation, mCameraId);
        mCameraDisplayOrientation = mDisplayOrientation;
        mUI.setDisplayOrientation(mDisplayOrientation);
        if (mFocusManager != null) {
            mFocusManager.setDisplayOrientation(mDisplayOrientation);
        }
        // Change the camera display orientation
        if (mCameraDevice != null) {
            mCameraDevice.setDisplayOrientation(mCameraDisplayOrientation);
        }
    }

    /** Only called by UI thread. */
    private void setupPreview() {
        mFocusManager.resetTouchFocus();
        startPreview();
    }

    /** This can run on a background thread, post any view updates to MainHandler. */
    private void startPreview() {
        if (mPaused || mCameraDevice == null) {
            return;
        }

         // Any decisions we make based on the surface texture state
         // need to be protected.
        SurfaceTexture st = mUI.getSurfaceTexture();
        if (st == null) {
            Log.w(TAG, "startPreview: surfaceTexture is not ready.");
            return;
        }

        if (!mCameraPreviewParamsReady) {
            Log.w(TAG, "startPreview: parameters for preview is not ready.");
            return;
        }
        mCameraDevice.setErrorCallback(mErrorCallback);
        // ICS camera frameworks has a bug. Face detection state is not cleared 1589
        // after taking a picture. Stop the preview to work around it. The bug
        // was fixed in JB.
        if (mCameraState != PREVIEW_STOPPED /*&& !isContinueTakePicture()*/) {
            stopPreview();
        }

        setDisplayOrientation();

        if (!mSnapshotOnIdle) {
            // If the focus mode is continuous autofocus, call cancelAutoFocus to
            // resume it because it may have been paused by autoFocus call.
            if (CameraUtil.FOCUS_MODE_CONTINUOUS_PICTURE.equals(mFocusManager.getFocusMode())) {
                mCameraDevice.cancelAutoFocus();
            }
            mFocusManager.setAeAwbLock(false); // Unlock AE and AWB.
        }
        setCameraParameters(UPDATE_PARAM_ALL);
//        updateSettingsMutex(); // SPRD: Before prievew start ,paramter mutex
                               // must be update.
        // Let UI set its expected aspect ratio
        mCameraDevice.setPreviewTexture(st);

        Log.v(TAG, "startPreview");
        mCameraDevice.startPreview();
        mFocusManager.onPreviewStarted();
        onPreviewStarted();
        mUI.enableSwitchCameraButton(true);//add by sprd for bug456
        if (mSnapshotOnIdle || mActivity.isAutoCapture()) {
            mHandler.post(mDoSnapRunnable);
        }
    }

    @Override
    public void stopPreview() {
        if (mCameraDevice != null && mCameraState != PREVIEW_STOPPED) {
            Log.v(TAG, "stopPreview");
            mCameraDevice.stopPreview();
            mFaceDetectionStarted = false;
        }
        setCameraState(PREVIEW_STOPPED);
        if (mFocusManager != null) mFocusManager.onPreviewStopped();
    }

    @SuppressWarnings("deprecation")
    private void updateCameraParametersInitialize() {
        // Reset preview frame rate to the maximum because it may be lowered by
        // video camera application.
        int[] fpsRange = CameraUtil.getPhotoPreviewFpsRange(mParameters);
        if (fpsRange != null && fpsRange.length > 0) {
            mParameters.setPreviewFpsRange(
                    fpsRange[Parameters.PREVIEW_FPS_MIN_INDEX],
                    fpsRange[Parameters.PREVIEW_FPS_MAX_INDEX]);
        }

        mParameters.set(CameraUtil.RECORDING_HINT, CameraUtil.FALSE);

        // Disable video stabilization. Convenience methods not available in API
        // level <= 14
        String vstabSupported = mParameters.get("video-stabilization-supported");
        if ("true".equals(vstabSupported)) {
            mParameters.set("video-stabilization", "false");
        }
    }

    private void updateCameraParametersZoom() {
        // Set zoom.
        if (mParameters.isZoomSupported()) {
            mParameters.setZoom(mZoomValue);
        }
    }

    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
    private void setAutoExposureLockIfSupported() {
        if (mAeLockSupported) {
            mParameters.setAutoExposureLock(mFocusManager.getAeAwbLock());
        }
    }

    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
    private void setAutoWhiteBalanceLockIfSupported() {
        if (mAwbLockSupported) {
            mParameters.setAutoWhiteBalanceLock(mFocusManager.getAeAwbLock());
        }
    }

    private void setFocusAreasIfSupported() {
        if (mFocusAreaSupported) {
            mParameters.setFocusAreas(mFocusManager.getFocusAreas());
        }
    }

    private void setMeteringAreasIfSupported() {
        if (mMeteringAreaSupported) {
            mParameters.setMeteringAreas(mFocusManager.getMeteringAreas());
        }
    }

    private boolean updateCameraParametersPreference() {
        CameraUtil.P(DEBUG, TAG, "updateCameraParametersPreference start");
        setAutoExposureLockIfSupported();
        setAutoWhiteBalanceLockIfSupported();
        setFocusAreasIfSupported();
        setMeteringAreasIfSupported();

        // Set picture size.
        String pictureSize =
            mPreferences.getString(CameraSettings.KEY_PICTURE_SIZE, null);
        if (pictureSize == null) {
            CameraSettings.initialCameraPictureSize(mActivity, mParameters);
        } else {
            List<Size> supported = mParameters.getSupportedPictureSizes();
            CameraSettings.setCameraPictureSize(pictureSize, supported, mParameters);
        }
        Size size = mParameters.getPictureSize();

        // Set a preview size that is closest to the viewfinder height and has
        // the right aspect ratio.
        List<Size> sizes = mParameters.getSupportedPreviewSizes();
        Size optimalSize = CameraUtil.getOptimalPreviewSize(
            mActivity, sizes, (double) size.width / size.height);
        Size original = mParameters.getPreviewSize();
        if (!original.equals(optimalSize)) {
            mParameters.setPreviewSize(optimalSize.width, optimalSize.height);

            // Zoom related settings will be changed for different preview
            // sizes, so set and read the parameters to get latest values
            if (mHandler.getLooper() == Looper.myLooper()) {
                // On UI thread only, not when camera starts up
                setupPreview();
            } else {
                mCameraDevice.setParameters(mParameters);
            }
            mParameters = mCameraDevice.getParameters();
        }

        if(optimalSize.width != 0 && optimalSize.height != 0) {
            mUI.updatePreviewAspectRatio(
                (float) optimalSize.width / (float) optimalSize.height);
        }
        Log.v(TAG, "Preview size is " + optimalSize.width + "x" + optimalSize.height);


        // Since changing scene mode may change supported values, set scene mode
        // first. HDR is a scene mode. To promote it in UI, it is stored in a
        // separate preference.
        String onValue = mActivity.getString(R.string.setting_on_value);
        String hdr = mPreferences.getString(
            CameraSettings.KEY_CAMERA_HDR,
            mActivity.getString(R.string.pref_camera_hdr_default));
        String hdrPlus = mPreferences.getString(
            CameraSettings.KEY_CAMERA_HDR_PLUS,
            mActivity.getString(R.string.pref_camera_hdr_plus_default));
        boolean hdrOn = onValue.equals(hdr);
        boolean hdrPlusOn = onValue.equals(hdrPlus);

        boolean doGcamModeSwitch = false;
        if (hdrPlusOn && GcamHelper.hasGcamCapture()) {
            // Kick off mode switch to gcam.
            doGcamModeSwitch = true;
        } else {
            mSceneMode = (hdrOn ?
                CameraUtil.SCENE_MODE_HDR :
                mPreferences.getString(
                    CameraSettings.KEY_SCENE_MODE,
                    mActivity.getString(R.string.pref_camera_scenemode_default)));
            if(hdrOn){
                mParameters.setExposureCompensation(0);
            }
        }
        if (CameraUtil.isSupported(mSceneMode, mParameters.getSupportedSceneModes())) {
            if (!mParameters.getSceneMode().equals(mSceneMode)) {
                mParameters.setSceneMode(mSceneMode);

                // Setting scene mode will change the settings of flash mode,
                // white balance, and focus mode. Here we read back the
                // parameters, so we can know those settings.
                mCameraDevice.setParameters(mParameters);
                mParameters = mCameraDevice.getParameters();
            }
        } else {
            mSceneMode = mParameters.getSceneMode();
            if (mSceneMode == null) {
                mSceneMode = Parameters.SCENE_MODE_AUTO;
            }
        }

        boolean hdrSupported = CameraUtil.isSupported(Parameters.SCENE_MODE_HDR,
                mParameters.getSupportedSceneModes());
        mUI.setHdrSupported(hdrSupported);
        boolean flashSupported = CameraSettings.VALUE_TRUE.equals(
                mParameters.get(CameraSettings.KEY_HAL_FLASH_SUPPORTED));
        mUI.setFlashSupported(flashSupported);

        /** SPRD: set HDR property after reset ZSL property @{ */
        if (mZSLController != null) {
            boolean debug_reset_zsl =
                mZSLController.proxyResetSwitcherValue(mPreferences, mParameters, hdrOn);
            if(debug_reset_zsl && mZSLController.switchOn()) {
                mUI.setZSLEnable(true);
            } else {
                mUI.setZSLEnable(false);
            }
            Log.d(TAG, "we need reset ZSL value to device? " + debug_reset_zsl);
        }
        /** @} */

        // Set exposure compensation
        int value = CameraSettings.readExposure(mPreferences);
        int max = mParameters.getMaxExposureCompensation();
        int min = mParameters.getMinExposureCompensation();
        if (value >= min && value <= max) {
            mParameters.setExposureCompensation(value);
        } else {
            Log.w(TAG, "invalid exposure range: " + value);
        }

        if (Parameters.SCENE_MODE_AUTO.equals(mSceneMode)) {
            // Set flash mode.
            if(mZSLController.switchOff()) {
                String flashMode = mPreferences.getString(
                    CameraSettings.KEY_FLASH_MODE,
                    mActivity.getString(R.string.pref_camera_flashmode_default));
                List<String> supportedFlash = mParameters.getSupportedFlashModes();
                if (CameraUtil.isSupported(flashMode, supportedFlash)) {
                    mParameters.setFlashMode(flashMode);
                } else {
                    flashMode = mParameters.getFlashMode();
                    if (flashMode == null) {
                        flashMode =
                        mActivity.getString(R.string.pref_camera_flashmode_no_flash);
                    }
                }
            } else { // SPRD: set flash off when ZSL is on
                mParameters.setFlashMode(Parameters.FLASH_MODE_OFF);
            }

            // Set white balance parameter.
            String whiteBalance = mPreferences.getString(
                    CameraSettings.KEY_WHITE_BALANCE,
                    mActivity.getString(R.string.pref_camera_whitebalance_default));
            if (CameraUtil.isSupported(
                    whiteBalance, mParameters.getSupportedWhiteBalance())) {
                mParameters.setWhiteBalance(whiteBalance);
            } else {
                whiteBalance = mParameters.getWhiteBalance();
                if (whiteBalance == null) {
                    whiteBalance = Parameters.WHITE_BALANCE_AUTO;
                }
            }

            // Set focus mode.
            mFocusManager.overrideFocusMode(null);
            mParameters.setFocusMode(mFocusManager.getFocusMode());
        } else {
            mFocusManager.overrideFocusMode(mParameters.getFocusMode());
        }

        if (mContinuousFocusSupported && ApiHelper.HAS_AUTO_FOCUS_MOVE_CALLBACK) {
            updateAutoFocusMoveCallback();
        }

        /* SPRD: Set Antibanding Value To FW.*/
        String antibanding = mPreferences.getString(
            CameraSettings.KEY_CAMERA_ANTIBANDING,
            mActivity.getString(R.string.pref_camera_antibanding_entryvalue_50));
        if (CameraUtil.isSupported(antibanding, mParameters.getSupportedAntibanding())) {
            mParameters.setAntibanding(antibanding);
        }

        /* SPRD: Set ISO Value To FW.*/
//        String camera_iso = mPreferences.getString(
//            CameraSettings.KEY_CAMERA_ISO,
//            mActivity.getString(R.string.pref_entry_value_auto));
//        if (CameraUtil.isSupported(camera_iso, mParameters.getSupportedISO())) {
//            mParameters.setISO(camera_iso);
//        }

        /* SPRD: Set Color Effect Value To FW.*/
        String color_effect = mPreferences.getString(
            CameraSettings.KEY_CAMERA_COLOR_EFFECT,
            mActivity.getString(R.string.pref_entry_value_none));
        if (CameraUtil.isSupported(color_effect, mParameters.getSupportedColorEffects())) {
            mParameters.setColorEffect(color_effect);
        }

        /* SPRD: Set CONTRAST Value To FW.*/
//        String contrast = mPreferences.getString(
//            CameraSettings.KEY_CAMERA_VIDEO_CONTRAST,
//            mActivity.getString(R.string.pref_entry_value_three));
//        if (CameraUtil.isSupported(contrast, mParameters.getSupportedContrast())) {
//            mParameters.setContrast(contrast);
//        }


        // Set JPEG quality.
        // fixed bug 128513 start
        // Sometime "CameraStartUpThread" initialize speed to fast more than main thread,
        // But "update hardware parameters" will be call back twice, so don't be worry can
        // not re-set "JpegQuality" property on the hardware.
        if (mJpegQualityController != null) {
            String quality = mPreferences.getString(
                CameraSettings.KEY_CAMERA_JPEG_QUALITY,
                mActivity.getString(R.string.pref_camera_jpegh_quality_entry_value_super_hight));
            int jpegQuality = mJpegQualityController.findJpegQuality(quality);
            mParameters.setJpegQuality(jpegQuality);
        }
        // fixed bug 128513 end

        /* SPRD: Set Camera Metering Value To FW.*/
//        String metering = mPreferences.getString(
//            CameraSettings.KEY_CAMERA_METERING,
//            mActivity.getString(R.string.pref_camera_metering_entry_value_frame_average));
//        if (CameraUtil.isSupported(metering, mParameters.getSupportedAutoExposureModes())) {
//            mParameters.setAutoExposureMode(metering);
//        } else {
//            metering = mParameters.getAutoExposureMode();
//        }

        // Set brightness
//        String brightness = mPreferences.getString(
//            CameraSettings.KEY_CAMERA_BRIGHTNESS,
//            mActivity.getString(R.string.pref_entry_value_three));
//        if (isSupported(brightness, mParameters.getSupportedBrightness())) {
//            mParameters.setBrightness(brightness);
//        }

        String sharpness = mPreferences.getString(
            CameraSettings.KEY_CAMERA_SHARPNESS,
            mActivity.getString(R.string.pref_entry_value_three));
//        if (isSupported(sharpness, mParameters.getSupportedSharpness())) {
//            mParameters.setSharpness(sharpness);
//        } else {
//            sharpness = mParameters.getSharpness();
//        }

        String saturation = mPreferences.getString(
            CameraSettings.KEY_CAMERA_SATURATION,
            mActivity.getString(R.string.pref_entry_value_three));
//        if (isSupported(saturation, mParameters.getSupportedSaturation())) {
//            mParameters.setSaturation(saturation);
//        } else {
//            saturation = mParameters.getSaturation();
//        }

        String burst = mPreferences.getString(
            CameraSettings.KEY_CAMERA_CONTINUOUS_CAPTURE, CameraSettings.DETAULT_PICTURE_NUMBER);
        if (mIsImageCaptureIntent) {
            burst = CameraSettings.DETAULT_PICTURE_NUMBER;
        }
        if (burst != null ) {
            mParameters.set(CameraSettings.KEY_CAPTURE_MODE, burst);
        }

        /* @{ SPRD: fix bug 273860 start */
        String val = mPreferences.getString(
                CameraSettings.KEY_TIMER,
                mActivity.getString(R.string.pref_camera_timer_default));
        int seconds = Integer.parseInt(val);
        if (seconds > 0) mUI.instantiateCountDown();
        /* end }@ */

        CameraUtil.P(DEBUG, TAG, "updateCameraParametersPreference end");
        return doGcamModeSwitch;
    }

    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
    private void updateAutoFocusMoveCallback() {
        if (mParameters.getFocusMode().equals(CameraUtil.FOCUS_MODE_CONTINUOUS_PICTURE)) {
            mCameraDevice.setAutoFocusMoveCallback(mHandler,
                    (CameraAFMoveCallback) mAutoFocusMoveCallback);
        } else {
            mCameraDevice.setAutoFocusMoveCallback(null, null);
        }
    }

    // We separate the parameters into several subsets, so we can update only
    // the subsets actually need updating. The PREFERENCE set needs extra
    // locking because the preference can be changed from GLThread as well.
    private void setCameraParameters(int updateSet) {
        boolean doModeSwitch = false;

        if ((updateSet & UPDATE_PARAM_INITIALIZE) != 0) {
            updateCameraParametersInitialize();
        }

        if ((updateSet & UPDATE_PARAM_ZOOM) != 0) {
            updateCameraParametersZoom();
        }

        if ((updateSet & UPDATE_PARAM_PREFERENCE) != 0) {
            doModeSwitch = updateCameraParametersPreference();
        }

        if (DEBUG) {
            String message = mParameters.flatten();
            CameraUtil.P(DEBUG, TAG, message);
        }
        mCameraDevice.setParameters(mParameters);

        // Switch to gcam module if HDR+ was selected
        if (doModeSwitch && !mIsImageCaptureIntent) {
            mHandler.sendEmptyMessage(SWITCH_TO_GCAM_MODULE);
        }
    }

    // If the Camera is idle, update the parameters immediately, otherwise
    // accumulate them in mUpdateSet and update later.
    private void setCameraParametersWhenIdle(int additionalUpdateSet) {
        mUpdateSet |= additionalUpdateSet;
        if (mCameraDevice == null) {
            // We will update all the parameters when we open the device, so
            // we don't need to do anything now.
            mUpdateSet = 0;
            return;
        } else if (isCameraIdle()) {
            setCameraParameters(mUpdateSet);
            //orig
            //updateSceneMode();
            updateSettingsMutex();
            mUpdateSet = 0;
        } else {
            if (!mHandler.hasMessages(SET_CAMERA_PARAMETERS_WHEN_IDLE)) {
                mHandler.sendEmptyMessageDelayed(
                        SET_CAMERA_PARAMETERS_WHEN_IDLE, 1000);
            }
        }
    }

    @Override
    public boolean isCameraIdle() {
        return (mCameraState == IDLE) ||
                (mCameraState == PREVIEW_STOPPED) ||
                ((mFocusManager != null) && mFocusManager.isFocusCompleted()
                        && (mCameraState != SWITCHING_CAMERA));
    }

    @Override
    public boolean isImageCaptureIntent() {
        Intent intent = mActivity.getIntent();
        String action = intent.getAction();
        mActivity.checkIntent(intent);
        return (MediaStore.ACTION_IMAGE_CAPTURE.equals(action)
                || CameraActivity.ACTION_IMAGE_CAPTURE_SECURE.equals(action));
    }

    private void setupCaptureParams() {
        Bundle myExtras = mActivity.getIntent().getExtras();
        if (myExtras != null) {
            mSaveUri = (Uri) myExtras.getParcelable(MediaStore.EXTRA_OUTPUT);
            mCropValue = myExtras.getString("crop");
        }
    }

    @Override
    public void onSharedPreferenceChanged() {
        // ignore the events after "onPause()"
        if (mPaused) return;

        boolean recordLocation = RecordLocationPreference.get(
                mPreferences, mContentResolver);
        mLocationManager.recordLocation(recordLocation);

        setCameraParametersWhenIdle(UPDATE_PARAM_PREFERENCE);
        sFreezeFrameControl.proxySharedPreferenceChanged(); //SPRD:Add for freeze_display
        mUI.updateOnScreenIndicators(mParameters, mPreferenceGroup, mPreferences);
        mUI.updateControlsTop(mPreferenceGroup, mParameters);
        ListPreference prefStorage =
            mPreferenceGroup.findPreference(CameraSettings.KEY_CAMERA_STORAGE_PATH);
        StorageUtil utilStorage = StorageUtil.newInstance();
        String patch = utilStorage.getStoragePath(mActivity, CameraUtil.MODE_CAMERA);
        if(patch != null){
            prefStorage.setStorageValue(patch);
        }
    }

    @Override
    public void onCameraPickerClicked(int cameraId) {
        if (mPaused || mPendingSwitchCameraId != -1) return;

        mPendingSwitchCameraId = cameraId;

        Log.v(TAG, "Start to switch camera. cameraId=" + cameraId);
        // We need to keep a preview frame for the animation before
        // releasing the camera. This will trigger onPreviewTextureCopied.
        //TODO: Need to animate the camera switch
        switchCamera();
    }

    // Preview texture has been copied. Now camera can be released and the
    // animation can be started.
    @Override
    public void onPreviewTextureCopied() {
        mHandler.sendEmptyMessage(SWITCH_CAMERA);
    }

    @Override
    public void onCaptureTextureCopied() {
    }

    @Override
    public void onUserInteraction() {
        if (!mActivity.isFinishing()) keepScreenOnAwhile();
    }

    private void resetScreenOn() {
        mHandler.removeMessages(CLEAR_SCREEN_DELAY);
        mActivity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
    }

    private void keepScreenOnAwhile() {
        mHandler.removeMessages(CLEAR_SCREEN_DELAY);
        mActivity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        mHandler.sendEmptyMessageDelayed(CLEAR_SCREEN_DELAY, SCREEN_DELAY);
    }

    @Override
    public void onOverriddenPreferencesClicked() {
        if (mPaused) return;
        mUI.showPreferencesToast();
    }

    private void showTapToFocusToast() {
        // TODO: Use a toast?
        new RotateTextToast(mActivity, R.string.tap_to_focus, 0).show();
        // Clear the preference.
        Editor editor = mPreferences.edit();
        editor.putBoolean(CameraSettings.KEY_CAMERA_FIRST_USE_HINT_SHOWN, false);
        editor.apply();
    }

    private void initializeCapabilities() {
        mInitialParams = mCameraDevice.getParameters();
        mFocusAreaSupported = CameraUtil.isFocusAreaSupported(mInitialParams);
        mMeteringAreaSupported = CameraUtil.isMeteringAreaSupported(mInitialParams);
        mAeLockSupported = CameraUtil.isAutoExposureLockSupported(mInitialParams);
        mAwbLockSupported = CameraUtil.isAutoWhiteBalanceLockSupported(mInitialParams);
        mContinuousFocusSupported = mInitialParams.getSupportedFocusModes().contains(
                CameraUtil.FOCUS_MODE_CONTINUOUS_PICTURE);
    }

    @Override
    public void onCountDownFinished() {
        mSnapshotOnIdle = false;
        if (mUI != null && isContinueTakePicture()) {
            mUI.enableBurstScreenHint(true);
        }
        mFocusManager.doSnap();
        mFocusManager.onShutterUp();
        // SPRD: HDR screen hint supported
        if (mUI != null) {
            mUI.enableHdrScreenHint(true, mPreferences);
        }
    }

    @Override
    public void onShowSwitcherPopup() {
        mUI.onShowSwitcherPopup();
    }

    @Override
    public int onZoomChanged(int index) {
        // Not useful to change zoom value when the activity is paused.
        if (mPaused) return index;
        mZoomValue = index;
        if (mParameters == null || mCameraDevice == null) return index;
        // Set zoom parameters asynchronously
        mParameters.setZoom(mZoomValue);
        mCameraDevice.setParameters(mParameters);
        Parameters p = mCameraDevice.getParameters();
        if (p != null) return p.getZoom();
        return index;
    }

    @Override
    public int getCameraState() {
        return mCameraState;
    }

    @Override
    public void onQueueStatus(boolean full) {
        mUI.enableShutter(!full);
        if (full && sFreezeFrameControl != null
                && sFreezeFrameControl.isFreezeFrame()) {
            Uri uri = null;
            sFreezeFrameControl.proxyRunLoadProxy(uri);
        }
        if (mIsTakingPicture &&
                mActivity.getStorageSpaceBytes() <= Storage.LOW_STORAGE_THRESHOLD_BYTES) {
            Log.i(TAG, "Not enough space or storage not ready. remaining="
                    + mActivity.getStorageSpaceBytes());
            updateCameraControls();
            mIsTakingPicture = false;
        }
    }

    @Override
    public void onQueueEmpty() {
        if (mContinuousCaptureCount > 0) {
            return;
        }
        if (isContinueTakePicture()) {
            updateCameraControls();
            mIsTakingPicture = false;
        }
    }

    @Override
    public void onMediaSaveServiceConnected(MediaSaveService s) {
        // We set the listener only when both service and shutterbutton
        // are initialized.
        if (mFirstTimeInitialized) {
            s.setListener(this);
        }
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {
    }

    @Override
    public void onSensorChanged(SensorEvent event) {
        int type = event.sensor.getType();
        float[] data;
        if (type == Sensor.TYPE_ACCELEROMETER) {
            data = mGData;
        } else if (type == Sensor.TYPE_MAGNETIC_FIELD) {
            data = mMData;
        } else {
            // we should not be here.
            return;
        }
        for (int i = 0; i < 3 ; i++) {
            data[i] = event.values[i];
        }
        float[] orientation = new float[3];
        SensorManager.getRotationMatrix(mR, null, mGData, mMData);
        SensorManager.getOrientation(mR, orientation);
        mHeading = (int) (orientation[0] * 180f / Math.PI) % 360;
        if (mHeading < 0) {
            mHeading += 360;
        }
    }

    @Override
    public void onPreviewFocusChanged(boolean previewFocused) {
        mUI.onPreviewFocusChanged(previewFocused);
    }

    @Override
    public boolean arePreviewControlsVisible() {
        return mUI.arePreviewControlsVisible();
    }

    // For debugging only.
    public void setDebugUri(Uri uri) {
        mDebugUri = uri;
    }

    // For debugging only.
    private void saveToDebugUri(byte[] data) {
        if (mDebugUri != null) {
            OutputStream outputStream = null;
            try {
                outputStream = mContentResolver.openOutputStream(mDebugUri);
                outputStream.write(data);
                outputStream.close();
            } catch (IOException e) {
                Log.e(TAG, "Exception while writing debug jpeg file", e);
            } finally {
                CameraUtil.closeSilently(outputStream);
            }
        }
    }

/* Below is no longer needed, except to get rid of compile error
 * TODO: Remove these
 */

    // TODO: Delete this function after old camera code is removed
    /* SPRD:Add for restore   @{ */
    @Override
    public void onRestorePreferencesClicked(AlertDialogPopup popup) {
        if (mPaused) return;
        Runnable runnableOk = new Runnable() {
            @Override
            public void run() {
                restorePreferences();
            }
        };
        Runnable runnableCancel = new Runnable() {
            @Override
            public void run() {
                mUI.dismissPopup(true);
            }
        };
        popup.setAlertDialog(
                mActivity.getString(R.string.pref_restore_detail),
                mActivity.getString(R.string.confirm_restore_message),
                mActivity.getString(R.string.dialog_ok), runnableOk,
                mActivity.getString(R.string.dialog_cancel), runnableCancel);

        mUI.showPopup(popup);
    }
    /* @} */
    /* SPRD:Add for restore   @{ */
    private void restorePreferences() {
        // Reset the zoom. Zoom value is not stored in preference.
        mZoomValue = 0;
        setCameraParametersWhenIdle(UPDATE_PARAM_ZOOM);
        mUI.initializeZoom(mParameters);

        if (mUI != null) {
            mUI.dismissPopup(false);
            Context context = mActivity;
            StoragePathPreference pathPreference = StoragePathPreference.getInstance(mActivity);
            pathPreference.clear();
            CameraSettings.restorePreferences(context, mPreferences, mParameters);
            mUI.reloadPreferences();
            onSharedPreferenceChanged();
        }

        StorageUtil utilStorage = StorageUtil.newInstance();
        utilStorage.syncThumbnailPath();
        mActivity.updateStorageSpaceAndHint();
    }
    /* @} */

    /**
     * SPRD:initialize CustomController, HDR,ZSL etc. @{
     */
    private void initializeCustomController() {
        mZSLController = new ZSLController(mPreferences);
    }
    /** @} */

    /* SPRD: porting new feature JPEG quality start @{ */
    private JpegQualityController mJpegQualityController;
    private class JpegQualityController {
        private static final String TAG = "CAM_CameraJpegQualityController";

        private static final String VAL_NORMAL = "normal";
        private static final String VAL_HIGHT  = "hight";
        private static final String VAL_SUPER  = "super";

        private static final int VAL_DEFAULT_QUALITY = 85;

        // default construct
        /*package*/ JpegQualityController() { }

        public int findJpegQuality(String quality) {
            int convertQuality = getConvertJpegQuality(quality);
            int result = VAL_DEFAULT_QUALITY;
            if (VAL_DEFAULT_QUALITY != convertQuality) {
                result = CameraProfile.getJpegEncodingQualityParameter(convertQuality);
            }
            Log.d(TAG, "findJpegQuality result = " + result);
            return result;
        }

        private int getConvertJpegQuality(String quality) {
            int result = VAL_DEFAULT_QUALITY;
            if (quality != null) {
            if (VAL_NORMAL.equals(quality))
                result = CameraProfile.QUALITY_LOW;
            else if (VAL_HIGHT.equals(quality))
                result = CameraProfile.QUALITY_MEDIUM;
            else if (VAL_SUPER.equals(VAL_SUPER))
                result = CameraProfile.QUALITY_HIGH;
            }
            Log.d(TAG, "getConvertJpegQuality result = " + result);
            return result;
       }
    }
    /* }@ dev new feature jpeg quality end */

    // onClick handler for R.id.btn_switch
    public void onSwitchButtonClicked() {
        // need to do
        // SPRD: bug 260858 Disable camera PickerButton when take picture
        if (!mEnableCameraSet || !mEnableTopButton || !isCameraIdle() || mUI.isCountingDown())
            return;
        if (mPreferenceGroup == null)
            return;
        ListPreference pref =
            mPreferenceGroup.findPreference(CameraSettings.KEY_CAMERA_ID);
        if (pref != null) {
            mUI.enableSwitchCameraButton(false);//add by sprd for bug456
            int index = pref.findIndexOfValue(pref.getValue());
            CharSequence[] values = pref.getEntryValues();
            // SPRD: check "values" is null for monkey
            CameraUtil.P(DEBUG, TAG, "onSwitchButtonClicked values=" + Arrays.toString(values) + ", index=" + index);
            int valuesLength = 0;
            if (values != null && (valuesLength = values.length) > 0) {
                index = (index + 1) % valuesLength;
                int newCameraId = Integer.parseInt((String) values[index]);
                pref.setValue("" + newCameraId);
                onCameraPickerClicked(newCameraId);
            }
        }
    }

    // onClick handler for R.id.btn_hdr
    public void onHdrButtonClicked() {
        // SPRD: bug 260858 disable HdrButton when take picture
        if(!mEnableCameraSet || !isCameraIdle() || mUI.isCountingDown()) return;
        String valueOn = mActivity.getString(R.string.setting_on_value);
        String valueOff = mActivity.getString(R.string.setting_off_value);
        String hdrValue = mPreferences.getString(CameraSettings.KEY_CAMERA_HDR, valueOff);

        // change current HDR state in the preferences
        boolean switcherOn = !(valueOn.equals(hdrValue));
        String changedValue = (switcherOn ? valueOn : valueOff);
        // reset HDR state to preferences
        Editor edit = mPreferences.edit();
        edit.putString(CameraSettings.KEY_CAMERA_HDR, changedValue);
//        if (changedValue.equals(valueOn) && isContinueTakePicture()) {
//            edit.putString(CameraSettings.KEY_CAMERA_CONTINUOUS_CAPTURE, "1");
//        }
        edit.apply();
        if (DEBUG) {
            String message =
                String.format("onHdrButtonClicked before=%s, after=%s",
                    new Object[] { hdrValue, changedValue });
            CameraUtil.P(DEBUG, TAG, message);
        }
        setCameraParametersWhenIdle(UPDATE_PARAM_PREFERENCE);
        mUI.updateOnScreenIndicators(mParameters, mPreferenceGroup, mPreferences);
        mUI.updateControlsTop(mPreferenceGroup, mParameters);
    }

    // onClick handler for R.id.btn_flash
    public void onFlashButtonClicked() {
        // SPRD: bug 260858 Disable FlashButton when take picture
        if(!mEnableTopButton || isHdrOn() || !isCameraIdle() ||
                mUI.isCountingDown() || mZSLController.switchOn()) return;
        setFlashMode();
        if (mParameters != null && mPreferenceGroup != null && mPreferences != null) {
            mUI.updateOnScreenIndicators(mParameters, mPreferenceGroup, mPreferences);
            mUI.updateControlsTop(mPreferenceGroup, mParameters);
        }
    }
    private void setFlashMode() {
        if (mPreferenceGroup == null) return;
        if (mCameraDevice == null) {
            Log.e(TAG, "The Camera is not initialized :" + mCameraId + ", aborting.");
            return;
        }
        ListPreference pref = mPreferenceGroup.findPreference(
                CameraSettings.KEY_FLASH_MODE);
        if (pref != null) {
            int index = pref.findIndexOfValue(pref.getValue());
            CharSequence[] values = pref.getEntryValues();
            index = (index + 1) % values.length;
            pref.setValue("" + values[index]);
        }
        if (Parameters.SCENE_MODE_AUTO.equals(mSceneMode)) {
            // Set flash mode.
            String flashMode =
                mPreferences.getString(
                    CameraSettings.KEY_FLASH_MODE,
                        mActivity.getString(R.string.pref_camera_flashmode_default));
            // if HDR switch is on, so we must reset flash to off
            // because camera device is unsupported HDR and flash both on
            // if (mHDRController != null && mHDRController.switchOn()) {
            // flashMode =
            // mActivity.getString(R.string.pref_camera_flashmode_default);
            // // if scene mode is burst and flash is on, so we must override
            // flash setting
            // } else if(mBurstController != null &&
            // mBurstController.switchOn()) {
            // flashMode =
            // mActivity.getString(R.string.pref_camera_flashmode_default);
            // }
            List<String> supportedFlash = mParameters.getSupportedFlashModes();
            if (isSupported(flashMode, supportedFlash)) {
                mParameters.setFlashMode(flashMode);
            } else {
                flashMode = mParameters.getFlashMode();
                if (flashMode == null) {
                    flashMode = mActivity.getString(R.string.pref_camera_flashmode_no_flash);
                }
            }

            // Set white balance parameter.
            String whiteBalance =
                mPreferences.getString(
                    CameraSettings.KEY_WHITE_BALANCE,
                        mActivity.getString(R.string.pref_camera_whitebalance_default));
            if (isSupported(whiteBalance, mParameters.getSupportedWhiteBalance())) {
                mParameters.setWhiteBalance(whiteBalance);
            } else {
                whiteBalance = mParameters.getWhiteBalance();
                if (whiteBalance == null) {
                    whiteBalance = Parameters.WHITE_BALANCE_AUTO;
                }
            }
        } else {
            mParameters.setFlashMode(Parameters.FLASH_MODE_OFF);
            mParameters.setWhiteBalance(Parameters.WHITE_BALANCE_AUTO);
        }
        mCameraDevice.setParameters(mParameters);
    }
    private static boolean isSupported(String value, List<String> supported) {
        return supported == null ? false : supported.indexOf(value) >= 0;
    }
    public void updateThumbnail(Bitmap bitmap){
        if(mIsImageCaptureIntent)
            bitmap = null;
        mUI.updateThumbnail(bitmap,mEnableCameraSet);
    }


    public void onCameraSettingClicked() {
        if(!mEnableCameraSet) return;
        mUI.onCameraSettingClicked();
    }
    public void onVideoCaptureShutterButtonClick() {

    }
    /* SPRD: dev multi-focus feature start @{ */
    public void onMultiTapUp(View view, List<Tuple<Integer, Integer>> pointers) {
        if (mPaused || mCameraDevice == null || !mFirstTimeInitialized
                || mCameraState == SNAPSHOT_IN_PROGRESS
                || mCameraState == SWITCHING_CAMERA
                || mCameraState == PREVIEW_STOPPED
                || sFreezeFrameControl.mFreezeVisible) {
            return;
        }

        // Check if metering area or focus area is supported.
        if (!mFocusAreaSupported && !mMeteringAreaSupported) return;
        mFocusManager.onMultiTapUp(pointers);
    }
    /* dev multi-focus feature end @} */

    /* SPRD: click 1st level popup title to dismiss start @{ */
    public void onSettingTitleClicked(View v) {
        mUI.onSettingTitleClicked(v);
    }
    /* click 1st level popup title to dismiss end @} */

    public void onPauseClicked() {
        // nothing to do
    }

    public void onStopClicked() {
        // nothing to do
    }

    /* SPRD:Add for freeze_display   @{ */
    public  FreezeFrameDisplayControl sFreezeFrameControl;
    private class FreezeFrameDisplayControl implements FreezeFrameDisplayView.ProxyFreezeFrameClick,Rotatable {
        private static final String TAG = "CAM_CameraFreezeFrameDisplayControl";
        private boolean sBurstSwitch;
        private boolean sFreezSwitch;
        private boolean mFreezeVisible;
        // SPRD: Save uri for Frezzeframe display
        private Uri mUri;
        // freeze-frame display view
        private FreezeFrameDisplayView sView;

        // default construct, initialize properties
        private FreezeFrameDisplayControl() {
            sBurstSwitch = isContinueTakePicture();
            sFreezSwitch = getBooleanByPreferenceKey(CameraSettings.KEY_FREEZE_FRAME_DISPLAY);
        }
        private void initialize() {
            FrameLayout layoutRoot =
                (FrameLayout)mActivity.findViewById(R.id.camera_layout_root);
            if (sView != null) {
                layoutRoot.removeView(sView);
            }
            LayoutInflater inflater = mActivity.getLayoutInflater();
            sView = (FreezeFrameDisplayView)
                inflater.inflate(R.layout.preview_camera_freeze_frame_display, null);
            layoutRoot.addView(sView);
            sView.setListener(this);
            sView.proxySetRotateDialogController(mRotateDialog);
        }

        // Runs in main thread
        /*package*/ boolean proxyDoNotTake() {
        /*
        * validate condition following:
        * 1、default by sView visibility state, if current state is visible, so anyway(camera key or soft key) can't take picture
        * 2、rejection soft key double click event and camera key quick click event
        */
            return (proxyDisplay()/* || (sFreezSwitch && (mCameraState != IDLE))*/);
        }

        /*package*/ boolean isFreezeFrame() {
            // SPRD: FixBug 269986,To obtain the values "FreezeDisplay".
            sFreezSwitch = getBooleanByPreferenceKey(CameraSettings.KEY_FREEZE_FRAME_DISPLAY);
            return (sFreezSwitch && !sBurstSwitch);
        }

        // Runs in main thread
        /*package*/ void proxyAnimation(boolean show) {
            initialize();
            if (show) {
                sView.proxyFadeIn(mIsImageCaptureIntent, mFreezeVisible);
                // we need reset FreezeFrameDisplayView orientation
                /* @{ SPRD: fix bug 255774 start */
                //sView.setOrientation(mOrientation, true);
                //sView.setOrientation(mOrientationCompensation, true);
                updateRotation(mDisplayOrientation);
                /* fix bug 255774 end @}*/
                // mCameraAppView.setVisibility(View.GONE);
                mFreezeVisible = true;
                mUI.hideUI();
                mUI.hideControlTopButton();
                // SPRD: bug 262968 Hide module switch view when FreezeFrame Display
            } else {
                mUI.showUI();
                mUI.showControlTopButton();
                mUI.updateControlsTop(mPreferenceGroup, mParameters);
                sView.proxyFadeOut();
                // mCameraAppView.setVisibility(View.VISIBLE);
                mFreezeVisible = false;
                updateCameraAppView();
                // SPRD: bug 262968 show module switch view when FreezeFrame unDisplay
            }
        }

        /*package*/ boolean proxyDisplay() {
            if (sView != null) {
                return sView.displayed();
            }
            return false;
        }

        /*package*/ void proxyRunLoadProxy(Uri uri) {
            mUri = uri;
            mActivity.setSwipingEnabled(false);
            if (sView == null) {
                initialize();
            }
            sView.runLoadResource(uri);
        }

        /* @{ SPRD: bug 251198 start */
        /*package*/ void proxyRunLoadProxy(byte [] jpagByte) {
            initialize();
            mActivity.setSwipingEnabled(false);
            sView.runLoadResource(jpagByte,mActivity.isAutoCapture());
        }
        /* bug 251198 end @} */

        /*package*/ void proxySharedPreferenceChanged() {
            /* Bug 268614 Burst and Freez Mutex @{ */
            if(isHdrOn()){
                return;
            }
            boolean bBurst = isContinueTakePicture();
            boolean bFreez = getBooleanByPreferenceKey(CameraSettings.KEY_FREEZE_FRAME_DISPLAY);
            Log.d(TAG, "proxySharedPreferenceChanged() before changed: Burst old = " + sBurstSwitch + ", new = "+
                    bBurst+",Freeze old = "+sFreezSwitch+", new = "+bFreez);

            boolean changed = false;
            if (bFreez == bBurst && !bFreez) {
                // if "val_freez" value is "false" and "val_freez" & "val_burst" value is
                // similar, we need validation previous burst and freeze value, if changed
                // we must call "mIndicatorControlContainer.reloadPreference()" method
                if (sBurstSwitch != bBurst || sFreezSwitch != bFreez) {
                    sBurstSwitch = changed;
                    sFreezSwitch = changed;
                    changed = true;
                }
            } else if (sBurstSwitch != bBurst) {
                sBurstSwitch = bBurst;
                sFreezSwitch = !bBurst;
                changed = true;
            } else if (sFreezSwitch != bFreez) {
                sFreezSwitch = bFreez;
                sBurstSwitch = !bFreez;
                changed = true;
            }
            Log.d(TAG, "proxySharedPreferenceChanged() is changed? "+changed);

            if (changed) {
                Log.d(TAG, "proxySharedPreferenceChanged() after changed: Burst old = " + sBurstSwitch + ", new = "+
                        bBurst+",Freeze old = "+sFreezSwitch+", new = "+bFreez);
                Editor editor = mPreferences.edit();

                String valueBurst;
                if (!sBurstSwitch) {
                    valueBurst = String.valueOf(VAL_DEFAULT_CAPTURE_COUNT);
                    editor.putString( CameraSettings.KEY_CAMERA_CONTINUOUS_CAPTURE, valueBurst);
                } else {
                    valueBurst = String.valueOf(getContinuousCount());
                    editor.putString( CameraSettings.KEY_CAMERA_CONTINUOUS_CAPTURE, valueBurst);
                }
                mParameters.set(CameraSettings.KEY_CAPTURE_MODE, valueBurst);
                String valueFreez = getStringBySwitchValue(sFreezSwitch);
                editor.putString(CameraSettings.KEY_FREEZE_FRAME_DISPLAY, valueFreez);
                editor.apply();
                Log.d(TAG, "proxySharedPreferenceChanged() after editor valueBurst = " + valueBurst + ",valueFreez = " + valueFreez);

                mCameraDevice.setParameters(mParameters);

                mUI.overrideSettings( CameraSettings.KEY_CAMERA_CONTINUOUS_CAPTURE, valueBurst);
                mUI.overrideSettings( CameraSettings.KEY_CAMERA_CONTINUOUS_CAPTURE, null);

                mUI.overrideSettings(CameraSettings.KEY_FREEZE_FRAME_DISPLAY, valueFreez);
                mUI.overrideSettings(CameraSettings.KEY_FREEZE_FRAME_DISPLAY, null);
            }
            /* @{ */
        }

        private boolean getBooleanByPreferenceKey(String key) {
            String val = mPreferences.getString(key, CameraSettings.VALUE_OFF);
            return (CameraSettings.VALUE_ON.equals(val));
        }

        private String getStringBySwitchValue(boolean value) {
            return (value ? CameraSettings.VALUE_ON : CameraSettings.VALUE_OFF);
        }

        private void proxyRestartCamera() {
            if (!mIsImageCaptureIntent /*&& (mCameraStartUpThread == null)*/) {
                startPreview();
                setCameraState(IDLE);
                startFaceDetection();
            }
        }

        @Override
        public void proxyRestartViews() {
            /* @{ SPRD: bug 251198 start */
            if (mIsImageCaptureIntent) {
                onCaptureCancelled();
                return;
            }
            /* bug 251198 end @} */
            mActivity.setSwipingEnabled(true);
            proxyRestartCamera();
            proxyAnimation(false);
        }

        @Override
        public void proxyDoneClicked() {
            /* @{ SPRD: bug 251198 start */
            if(mIsImageCaptureIntent) {
                onCaptureDone();
                return;
            }
            // SPRD: NotifyNewMedia when select save the freeze display picture
            Log.d(TAG,"proxyDoneClicked, mUri = "+mUri);
            if(mUri != null)
                mActivity.notifyNewMedia(mUri);
            /* bug 251198 end @} */
            proxyRestartViews();
        }

        @Override
        public void proxyFinishDeleted(boolean deleted) {
            Log.d(TAG, "main thread delete picture result = " + deleted);
            // update thumbnail
            if (deleted && !mIsImageCaptureIntent) {
                mActivity.updateThumbail();
                mUI.setPreviewThumbVisibility(View.VISIBLE);
            }
        }

        /* @{ SPRD: bug 251198 start */
        @Override
        public void proxyRetakeClicked() {
            // TODO Auto-generated method stub
            if(mIsImageCaptureIntent) {
                mJpegImageData = null;
                proxyRestartCamera();
                proxyAnimation(false);
                if (mPaused) return;
                mUI.hidePostCaptureAlert();
                startPreview();
                setCameraState(IDLE);
                startFaceDetection();
                return;
            }
            else return;
        }
        /* bug 251198 end @} */

        public void setOrientation(int orientation, boolean animation) {
            if (sView != null && proxyDisplay()) {
            }
        }

        // @{ SPRD: Update the view for freezeframe display begin
        public void updateFreezeUi() {
            if(mFreezeVisible) {
//                initialize();
                proxyAnimation(true);
                if(mUri != null) {
                    proxyRunLoadProxy(mUri);
                }
            }
        } // SPRD: Update the view for freezeframe display end @}

        // @{ SPRD: Change the rotation of views for freezeframe begin
        public void updateRotation(int rotation) {
            if(sView == null) return;
            switch (rotation) {
            case 180:
                sView.setRotationY(180);
                break;
            case 270:
                sView.setRotationX(180);
                break;
            default:
                ;
            }
            sView.updateFreezeChildUi(rotation);
        } // SPRD: Change the rotation of views for freezeframe end @}
    }
    /* @} */
    public void showSwitcher() {
        if(!mIsImageCaptureIntent)
            mUI.showSwitcher();
    }

    public void hideSwitcher() {
            mUI.hideSwitcher();
    }

    /** SPRD: get hdr state methods @{ */
    public boolean isHdrOn() {
        String onValue = mActivity.getString(R.string.setting_on_value);
        String hdr = mPreferences.getString(CameraSettings.KEY_CAMERA_HDR,
                mActivity.getString(R.string.pref_camera_hdr_default));
        return onValue.equals(hdr);
    }
    public boolean isHdrPlusOn() {
        String onValue = mActivity.getString(R.string.setting_on_value);
        String hdrPlus = mPreferences.getString(CameraSettings.KEY_CAMERA_HDR_PLUS,
                mActivity.getString(R.string.pref_camera_hdr_plus_default));
        return onValue.equals(hdrPlus);
    }
    /** @} */

    /** SPRD: Get the numbers when capture. */
    private int getContinuousCount() {
        String valueOff = mActivity.getString(R.string.setting_off_value);
        String hdrValue = mPreferences.getString(CameraSettings.KEY_CAMERA_HDR, valueOff);
        if (!valueOff.equals(hdrValue)) {
            mContinueTakePictureCount = 1;
        } else {
            String sValue = mPreferences.getString(CameraSettings.KEY_CAMERA_CONTINUOUS_CAPTURE,
                    String.valueOf(VAL_DEFAULT_CAPTURE_COUNT));
            mContinueTakePictureCount = (mIsImageCaptureIntent ? VAL_DEFAULT_CAPTURE_COUNT
                    : Integer.valueOf(sValue));
        }
        Log.d(TAG, "getContinuousCount=" + mContinueTakePictureCount);
        return mContinueTakePictureCount;
    }

    private boolean isContinueTakePicture() {
        if (getContinuousCount() > 1) {
            return true;
        }
        return false;
    }

    @Override
    public void hideControls() {
        mUI.hideControlsUI();
    }

    @Override
    public void showControls() {
        mUI.showControlsUI();
    }

    @Override
    public boolean isFreezeFrameDisplay() {
        if (sFreezeFrameControl != null) {
            return sFreezeFrameControl.proxyDisplay();
        }
        return false ;
    }

    private void updateCameraControls(){
        if (mUI == null) {
            return;
        }
        // SPRD: bug 260858
        mEnableTopButton = true;
        mEnableCameraSet = true;
        mUI.enableShutter(true);
        mUI.enableBurstScreenHint(false);

        showControls();
        if (!isFreezeFrameDisplay()) {
            // SPRD: bug 273960
            showSwitcher();
            mUI.showControlTopButton();
            mUI.updateControlsTop(mPreferenceGroup, mParameters);
        }
    }
}
